home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Games / WormWars / Source / engine.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-03-13  |  170.8 KB  |  4,915 lines

  1. /* $Filename: WormWars/Source/engine.c
  2.  * $VER:      WormWars 6.9
  3.  *
  4.  * © Copyright 2002 James R. Jacobs. Freely distributable.
  5.  */
  6.  
  7. #include <string.h>
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
  11. #include <assert.h>
  12. #define ASSERT
  13.  
  14. #include "stdafx.h"
  15. #include "diff.h"
  16. #include "same.h"
  17.  
  18. #define OTTER_UP    0
  19. #define OTTER_DOWN  1
  20. #define OTTER_LEFT  2
  21. #define OTTER_RIGHT 3
  22.  
  23. #define ARROWX               (FIELDX + 1)
  24. #define BONUSSPEEDUP         4 // 4 times more common on bonus levels
  25. #define NOSE                 2 // if (NOSE > PROTECTORS) nose disabled
  26. #define WORMQUEUELIMIT      15
  27. #define DOGQUEUELIMIT      120
  28. #define TIMELIMIT          599
  29. #define SECONDSPERLEVEL    120 // assert (SECONDSPERLEVEL <= TIMELIMIT);
  30. #define WEIGHT               5
  31.  
  32. // dog dormancy
  33. #define DORMANT              0
  34. #define AWAKENING            1
  35. #define CHASING             10
  36.  
  37. // population limits
  38. #define CREATURES           50
  39. #define MAGNETS             20
  40. #define PROTECTORS           2 // <=4!
  41. #define OCTOPI              12 // this limit applies only to predefined octopi
  42.  
  43. #define FREQ_BIRD          130
  44. #define FREQ_CLOUD          50
  45. #define FREQ_CLOUDFIRE      30
  46. #define FREQ_DOG            50
  47. #define FREQ_DRIP           10
  48. #define FREQ_FISH          105
  49. #define FREQ_GOAT           20
  50. #define FREQ_GOATFIRE       10
  51. #define FREQ_GOATMOVE        5
  52. #define FREQ_OCTOPUS        80
  53. #define FREQ_OCTOPUSFIRE    15
  54. #define FREQ_OCTOPUSSPIN     3
  55. #define FREQ_ORB            30
  56. #define FREQ_PENGUIN        20
  57. #define FREQ_SLIME          70
  58. #define FREQ_SLIMEGROW      65
  59. #define FREQ_TELEPORT      200
  60. #define FREQ_TIMEBOMB      210
  61.  
  62. #define SPEED_BIRD          10
  63. #define SPEED_CLOUD          9
  64. #define SPEED_DOG            3
  65. #define SPEED_DRIP           4
  66. #define SPEED_FISH          12
  67. #define SPEED_FRAGMENT       3
  68. #define SPEED_GOAT          16
  69. #define SPEED_MAGNET         9
  70. #define SPEED_MISSILE        6
  71. #define SPEED_OCTOPUS       16
  72. #define SPEED_ORB            6
  73. #define SPEED_OTTER         19
  74. #define SPEED_PENGUIN       11
  75. #define SPEED_TIMEBOMB      60
  76. #define SPEED_WHIRLWIND      1
  77.  
  78. #define HARDNESS_BIRD       50
  79. #define HARDNESS_CLOUD      50
  80. #define HARDNESS_DOG        50
  81. #define HARDNESS_DRIP       50
  82. #define HARDNESS_FISH       50
  83. #define HARDNESS_FRAGMENT   50
  84. #define HARDNESS_GOAT       50
  85. #define HARDNESS_MISSILE    50
  86. #define HARDNESS_OCTOPUS    50
  87. #define HARDNESS_OTTER      95
  88. #define HARDNESS_ORB        50
  89. #define HARDNESS_PENGUIN    10
  90. #define HARDNESS_TIMEBOMB   80
  91. #define HARDNESS_WHIRLWIND  90
  92.  
  93. #define DISTANCE_FAST        5
  94. #define DISTANCE_BIRD        3
  95. #define DISTANCE_NORMAL      4
  96. #define DISTANCE_NOSE        4
  97. #define DISTANCE_SLOW        3
  98. #define DISTANCE_VERYSLOW    2
  99.  
  100. #define POINTS_EMPTY         1
  101. #define POINTS_DYNAMITE      5
  102. #define POINTS_TURNSILVER    5
  103. #define POINTS_ENCLOSURE    10
  104. #define POINTS_SILVER       10
  105. #define POINTS_TURNGOLD     10
  106. #define POINTS_GOLD         20
  107. #define POINTS_LETTER      100
  108. #define POINTS_SKULL       100
  109.  
  110. #define  ADD_BOMB      5 // in squares radius
  111. #define  ADD_CLOCK    10 // in seconds
  112. #define  ADD_CUTTER   10 // in VERYSLOWs
  113. #define  ADD_FREEDOM  20 // in VERYSLOWs
  114. #define  ADD_ICE      10 // in VERYSLOWs
  115. #define  ADD_MODE     30 // in VERYSLOWs
  116. #define  ADD_TREASURE 10 // in seconds
  117. #define RAND_BOMB     25
  118. #define RAND_CLOCK    20
  119. #define RAND_CUTTER   20
  120. #define RAND_FREEDOM  50
  121. #define RAND_ICE       5
  122. #define RAND_MODE     40
  123. #define RAND_TREASURE 10
  124.  
  125. MODULE  void changefield(void);
  126. MODULE  void clearletters(void);
  127. MODULE  void death(void);
  128. MODULE  void fastloop(void);
  129. MODULE  void killall(void);
  130. MODULE  void magnetloop(void);
  131. MODULE  void newhiscores(void);
  132. MODULE  void slowloop(void);
  133. MODULE  void ReadGameports(void);
  134.  
  135. MODULE  void bangdynamite(SBYTE x, SBYTE y, SBYTE player);
  136. MODULE  void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey);
  137. MODULE  void bothcol(SBYTE player, SBYTE x, SBYTE y);
  138. MODULE  void bouncegoatoctopus(UBYTE which, SBYTE x, SBYTE y);
  139. MODULE  void __inline change(SBYTE x, SBYTE y, UBYTE image);
  140. MODULE  void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize);
  141. MODULE  void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay);
  142. MODULE  void creatureloop(SBYTE which);
  143. MODULE  void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay);
  144. MODULE  void drawcause(SBYTE player, SBYTE state);
  145. MODULE  void drawletter(SBYTE letter, SBYTE state);
  146. MODULE  void newlevel(UBYTE player);
  147. MODULE  void orbsplit(SBYTE which);
  148. MODULE  void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot);
  149. MODULE  void putletter(void);
  150. MODULE  void ramming(SBYTE player);
  151. MODULE  void reflect(UBYTE which);
  152. MODULE  void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay);
  153. MODULE  void updatearrow(SBYTE arrowy);
  154. MODULE  void wormbullet(SBYTE player);
  155. MODULE  void wormletter(SBYTE player, UBYTE c);
  156. MODULE  void wormloop(SBYTE player);
  157. MODULE  void wormcol(SBYTE player, SBYTE x, SBYTE y);
  158.  
  159. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  160. MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  161. MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  162. MODULE void octopusfire(UBYTE which);
  163. MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter);
  164. MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which);
  165.  
  166. MODULE SWORD atleast(SWORD value, SWORD minimum);
  167. MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay);
  168. MODULE ABOOL bounceorb(UBYTE which, SBYTE x, SBYTE y);
  169. MODULE SBYTE bsign(SBYTE value);
  170. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode);
  171. MODULE SBYTE onlyworm(ABOOL alive);
  172. MODULE SBYTE slowdown(SBYTE speed, ABOOL nitro);
  173. MODULE SBYTE speedup(SBYTE speed, ABOOL nitro);
  174. MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception);
  175. MODULE SBYTE whichteleport(SBYTE x, SBYTE y);
  176. MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y);
  177.  
  178. MODULE void wormkillcreature(UBYTE player, UBYTE which);
  179. MODULE void createcreature(UBYTE species, UBYTE which, SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE player);
  180. MODULE ULONG arand(ULONG number);
  181. MODULE void protcreature(UBYTE player, UBYTE which);
  182. MODULE void wormcreature(UBYTE player, UBYTE which);
  183. MODULE void creaturecreature(UBYTE which1, UBYTE which2);
  184.  
  185. /* PRIVATE STRUCTURES -------------------------------------------------- */
  186.  
  187. struct
  188. {   SBYTE x, y, deltax, deltay;
  189.     ABOOL alive, moved, teleported, visible, reflected;
  190. } bullet[9];
  191. struct
  192. {   UWORD freq;
  193.     ULONG score;
  194. } object[LASTOBJECT + 1] =
  195. {   {1600,  60}, // AFFIXER
  196.     {  65,  20}, // AMMO
  197.     { 105,  20}, // ARMOUR
  198.     {  70,  50}, // BIAS
  199.     { 130,  30}, // BOMB
  200.     {  85,  10}, // BONUS
  201.     {1015,  60}, // CLOCK
  202.     { 370,  50}, // CONVERTER
  203.     { 285,  80}, // CUTTER
  204.     { 250,  90}, // CYCLONE
  205.     { 310,  20}, // ENCLOSER
  206.     { 500,  30}, // FREEDOM
  207.     { 210,  50}, // GROWER
  208.     {1900,  90}, // HEALER
  209.     { 950,  60}, // ICE
  210.     { 135,  60}, // LIFE
  211.     { 160,  80}, // LIGHTNING
  212.     { 925,  80}, // MAGNET
  213.     { 215,  40}, // MISSILE
  214.     { 635,  50}, // MULTIPLIER
  215.     { 380,  10}, // NITRO
  216.     { 235,  30}, // POWER
  217.     { 475,  50}, // PROTECTOR
  218.     { 210,  40}, // PULSE
  219.     { 300,  50}, // PUSHER
  220.     { 400,  40}, // REMNANTS
  221.     { 495,  30}, // SIDESHOT
  222.     { 600,  40}, // SLAYER
  223.     { 980,  40}, // SLOWER
  224.     { 730,  70}, // SWITCHER
  225.     {1400, 120}, // TREASURE
  226.     {3800, 140}  // UMBRELLA
  227. };
  228.  
  229. /*  -200    common
  230.     220-400 uncommon
  231.     420-980 rare
  232.     1000+   very rare */
  233.  
  234. struct
  235. {   SBYTE x, y, deltax, deltay, relx, rely;
  236.     ABOOL alive, last, visible;
  237. } protector[4][PROTECTORS + 1];
  238. struct
  239. {   SBYTE deltax, deltay;
  240. } thewormqueue[4][WORMQUEUELIMIT + 1];
  241. struct
  242. {   SBYTE deltax, deltay;
  243. } thedogqueue[CREATURES + 1][DOGQUEUELIMIT + 1];
  244. struct
  245. {   ABOOL alive;
  246.     SBYTE x, y, player;
  247.     UBYTE object;
  248. } magnet[MAGNETS + 1];
  249.  
  250. AGLOBAL UBYTE missileframes[4][MISSILEFRAMES + 1] =
  251. { { FIRSTMISSILE,
  252.     FIRSTMISSILEFRAME,
  253.     FIRSTMISSILEFRAME + 1,
  254.     FIRSTMISSILEFRAME + 2,
  255.     FIRSTMISSILEFRAME + 3,
  256.     FIRSTMISSILEFRAME + 4
  257.   },
  258.   { FIRSTMISSILE + 1,
  259.     FIRSTMISSILEFRAME + 5,
  260.     FIRSTMISSILEFRAME + 6,
  261.     FIRSTMISSILEFRAME + 7,
  262.     FIRSTMISSILEFRAME + 8,
  263.     FIRSTMISSILEFRAME + 9
  264.   },
  265.   { FIRSTMISSILE + 2,
  266.     FIRSTMISSILEFRAME + 10,
  267.     FIRSTMISSILEFRAME + 11,
  268.     FIRSTMISSILEFRAME + 12,
  269.     FIRSTMISSILEFRAME + 13,
  270.     FIRSTMISSILEFRAME + 14,
  271.   },
  272.   { FIRSTMISSILE + 3,
  273.     FIRSTMISSILEFRAME + 15,
  274.     FIRSTMISSILEFRAME + 16,
  275.     FIRSTMISSILEFRAME + 17,
  276.     FIRSTMISSILEFRAME + 18,
  277.     FIRSTMISSILEFRAME + 19
  278. } };
  279.  
  280.  
  281. UBYTE eachworm[4][2][9] =
  282. { { { GREENHEADUP,   GREENHEADUP,   GREENHEADUP,
  283.       GREENHEADLEFT, ANYTHING,      GREENHEADRIGHT,
  284.       GREENHEADDOWN, GREENHEADDOWN, GREENHEADDOWN
  285.     },
  286.     { GREENMODEUP,   GREENMODEUP,   GREENMODEUP,
  287.       GREENMODELEFT, ANYTHING,      GREENMODERIGHT,
  288.       GREENMODEDOWN, GREENMODEDOWN, GREENMODEDOWN
  289.   } },
  290.   { { REDHEADUP,     REDHEADUP,     REDHEADUP,
  291.       REDHEADLEFT,   ANYTHING,      REDHEADRIGHT,
  292.       REDHEADDOWN,   REDHEADDOWN,   REDHEADDOWN
  293.     },
  294.     { REDMODEUP,     REDMODEUP,     REDMODEUP,
  295.       REDMODELEFT,   ANYTHING,      REDMODERIGHT,
  296.       REDMODEDOWN,   REDMODEDOWN,   REDMODEDOWN
  297.   } },
  298.   { { BLUEHEADUP,    BLUEHEADUP,    BLUEHEADUP,
  299.       BLUEHEADLEFT,  ANYTHING,      BLUEHEADRIGHT,
  300.       BLUEHEADDOWN,  BLUEHEADDOWN,  BLUEHEADDOWN
  301.     },
  302.     { BLUEMODEUP,    BLUEMODEUP,    BLUEMODEUP,
  303.       BLUEMODELEFT,  ANYTHING,      BLUEMODERIGHT,
  304.       BLUEMODEDOWN,  BLUEMODEDOWN,  BLUEMODEDOWN
  305.   } },
  306.   { { YELLOWHEADUP,  YELLOWHEADUP,  YELLOWHEADUP,
  307.       YELLOWHEADLEFT,ANYTHING,      YELLOWHEADRIGHT,
  308.       YELLOWHEADDOWN,YELLOWHEADDOWN,YELLOWHEADDOWN
  309.     },
  310.     { YELLOWMODEUP,  YELLOWMODEUP,  YELLOWMODEUP,
  311.       YELLOWMODELEFT,ANYTHING,      YELLOWMODERIGHT,
  312.       YELLOWMODEDOWN,YELLOWMODEDOWN,YELLOWMODEDOWN
  313. } } };
  314.  
  315. /* Rules for variable types:
  316.  
  317. SBYTE is used for field coordinates and queue indexes
  318. UBYTE is used for field contents
  319. SWORD is used for frequencies
  320. ULONG is used for scores */
  321.  
  322. struct
  323. {   ABOOL alive, visible;
  324.     SBYTE x, y, deltax, deltay, pos, time, dir;
  325.     UBYTE dormant, multi, speed, last, oldlast, species, hardness, frame,
  326.           journey, going, then,
  327.           type; // type is worm 0-3 (for drips, missiles, dogs and birds)
  328.     SWORD freq;
  329.     ULONG score;
  330. } creature[CREATURES + 1];
  331.  
  332. // MODULE VARIABLES (used only within engine.c) ---------------------------
  333.  
  334. MODULE ABOOL banging  = FALSE,
  335.              first    = TRUE,
  336.              letters[LETTERS + 1],
  337.              enclosed = FALSE,
  338.              trainer;
  339. MODULE SBYTE lettertype, letterx, lettery, leveltype, treasurer;
  340. MODULE UBYTE infector[FIELDX + 1][FIELDY + 1], ice;
  341.  
  342. // GLOBAL VARIABLES -------------------------------------------------------
  343.  
  344. IMPORT ABOOL iso;
  345.  
  346. ABOOL anims      = TRUE,
  347.       clearthem  = FALSE,
  348.       modified   = FALSE,
  349.       randomflag = FALSE,
  350.       randomarray[MAXLEVELS + 1],
  351.       turbo      = FALSE;
  352. UBYTE board[MAXLEVELS + 1][FIELDX + 1][FIELDY + 1],
  353.       field[FIELDX + 1][FIELDY + 1];
  354. SBYTE a = GAMEOVER,
  355.       players,
  356.       level = 1, levels, reallevel, sourcelevel,
  357.       startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  358. SWORD secondsleft, secondsperlevel;
  359. TEXT  pathname[81],
  360.       date[DATELENGTH + 1],
  361.       times[TIMELENGTH + 1];
  362. ULONG delay, r;
  363.  
  364. AGLOBAL struct HiScoreStruct  hiscore[HISCORES + 1];
  365. AGLOBAL struct WormStruct     worm[4];
  366. AGLOBAL struct TeleportStruct teleport[MAXLEVELS + 1][4];
  367.  
  368. MODULE ABOOL blocked(UBYTE which, SBYTE deltax, SBYTE deltay)
  369. {   UBYTE c = field[xwrap(teleport[level][partner(which)].x + deltax)][ywrap(teleport[level][partner(which)].y + deltay)];
  370.     if (c == STONE || c == METAL || c == GOAT || c == OCTOPUS)
  371.         return TRUE;
  372.     else return FALSE;
  373. }
  374.  
  375. MODULE void bombblast(SBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey)
  376. {   SBYTE counter, downy, downymax, leftx, leftxmax, rightx, rightxmax, strength, uppy, uppymax, x, y;
  377.  
  378.     effect(FXUSE_BOMB);
  379.     strength = ADD_BOMB + arand(RAND_BOMB);
  380.  
  381.     leftxmax = centrex - strength;
  382.     if (leftxmax < 0)
  383.         leftxmax = 0;
  384.     rightxmax = centrex + strength;
  385.     if (rightxmax > FIELDX)
  386.         rightxmax = FIELDX;
  387.     uppymax = centrey - strength;
  388.     if (uppymax < 0)
  389.         uppymax = 0;
  390.     downymax = centrey + strength;
  391.     if (downymax > FIELDY)
  392.         downymax = FIELDY;
  393.  
  394.     leftx = centrex;
  395.     rightx = centrex;
  396.     uppy = centrey;
  397.     downy = centrey;
  398.     for (counter = 1; counter <= strength; counter++)
  399.     {   if (leftx > leftxmax)
  400.         {   leftx--;
  401.             for (y = uppy; y <= downy; y++)
  402.                 squareblast(triggerer, player, field[leftx][y], leftx, y, FALSE);
  403.         }
  404.         if (uppy > uppymax)
  405.         {   uppy--;
  406.             for (x = leftx; x <= rightx; x++)
  407.                 squareblast(triggerer, player, field[x][uppy], x, uppy, FALSE);
  408.         }
  409.         if (rightx < rightxmax)
  410.         {   rightx++;
  411.             for (y = downy; y >= uppy; y--)
  412.                 squareblast(triggerer, player, field[rightx][y], rightx, y, FALSE);
  413.         }
  414.         if (downy < downymax)
  415.         {   downy++;
  416.             for (x = rightx; x >= leftx; x--)
  417.                 squareblast(triggerer, player, field[x][downy], x, downy, FALSE);
  418. }   }   }
  419.  
  420. MODULE void bouncegoatoctopus(UBYTE which, SBYTE x, SBYTE y)
  421. {   UBYTE killed;
  422.  
  423.     if (field[x][y] == GOAT || field[x][y] == OCTOPUS || field[x][y] == FISH)
  424.     {   if (field[x][y] == GOAT)
  425.         {   effect(FXDEATH_GOAT);
  426.         }
  427.         killed = whichcreature(x, y, field[x][y], which);
  428.         creature[killed].alive = FALSE;
  429.         change(x, y, BONUS);
  430. }   }
  431.  
  432. MODULE ABOOL bounceorb(UBYTE which, SBYTE x, SBYTE y)
  433. {   if
  434.     (    field[x][y] == METAL
  435.      ||  field[x][y] == STONE
  436.      ||  field[x][y] == WOOD
  437.      ||  field[x][y] == GOAT
  438.      ||  field[x][y] == OCTOPUS
  439.      ||  field[x][y] == FISH
  440.      || (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  441.     )
  442.     {   return TRUE;
  443.     } else
  444.     {   return FALSE;
  445. }   }
  446.  
  447. MODULE SBYTE bsign(SBYTE value)
  448. {   if (value < 0)
  449.         return (-1);
  450.     elif (value > 0)
  451.         return (1);
  452.     else return (0);
  453. }
  454.  
  455. MODULE void changefield(void)
  456. {   SBYTE x, y;
  457.  
  458.     if (randomflag && a == PLAYGAME && level)
  459.     {   do
  460.         {    sourcelevel = arand(levels - 1) + 1;
  461.         } while (randomarray[level]);
  462.         randomarray[level] = TRUE;
  463.     } else sourcelevel = level;
  464.  
  465.     for (x = 0; x <= FIELDX; x++)
  466.         for (y = 0; y <= FIELDY; y++)
  467.             field[x][y] = board[sourcelevel][x][y];
  468. }
  469.  
  470. void clearhiscores(void)
  471. {   SBYTE i;
  472.     
  473.     clearthem = FALSE;
  474.     for (i = 0; i <= HISCORES; i++)
  475.     {   hiscore[i].player = -1;
  476.         hiscore[i].level = 0;
  477.         hiscore[i].score = 0;
  478.         hiscore[i].fresh = FALSE;
  479.         hiscore[i].name[0] = 0;
  480.         hiscore[i].time[0] = 0;
  481.         hiscore[i].date[0] = 0;
  482. }   }
  483.  
  484. MODULE void clearletters(void)
  485. {   SBYTE which;
  486.  
  487.     for (which = 0; which <= LETTERS; which++)
  488.     {   letters[which] = FALSE;
  489.         drawletter(FIRSTLETTER + which, BLACK);
  490. }   }
  491.  
  492. MODULE void death(void)
  493. {   SBYTE pain, player;
  494.     UBYTE which;
  495.     ABOOL slow;
  496.  
  497.     for (player = 0; player <= 3; player++)
  498.     {   if (worm[player].lives)
  499.         {   if (!worm[player].alive)
  500.             {   slow = FALSE;
  501.                 pain = 0;
  502.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  503.                 {   if (player == worm[player].cause - FIRSTTAIL)
  504.                         pain = PAIN_FRIENDLYTAIL;
  505.                     else pain = PAIN_ENEMYTAIL;
  506.                     slow = TRUE;
  507.                 } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  508.                     pain = PAIN_WORMFIRE;
  509.                 elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  510.                     pain = PAIN_HEAD;
  511.                 elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  512.                     pain = PAIN_PROTECTOR;
  513.                 elif (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  514.                     pain = PAIN_MISSILE;
  515.                 elif (worm[player].cause >= FIRSTDRIP && worm[player].cause <= LASTDRIP)
  516.                     pain = PAIN_DRIP;
  517.                 else switch (worm[player].cause)
  518.                 {
  519.                 case FISH:
  520.                     pain = PAIN_FISH;
  521.                     slow = TRUE;
  522.                 case GOAT:
  523.                     pain = PAIN_GOAT;
  524.                     slow = TRUE;
  525.                 break;
  526.                 case OCTOPUS:
  527.                     pain = PAIN_OCTOPUS;
  528.                     slow = TRUE;
  529.                 break;
  530.                 case METAL:
  531.                     pain = PAIN_METAL;
  532.                     slow = TRUE;
  533.                 break;
  534.                 case REMNANTS:
  535.                     pain = PAIN_REMNANT;
  536.                     slow = TRUE;
  537.                 break;
  538.                 case SLIME:
  539.                     pain = PAIN_SLIME;
  540.                     slow = TRUE;
  541.                 break;
  542.                 case STONE:
  543.                     pain = PAIN_STONE;
  544.                     slow = TRUE;
  545.                 break;
  546.                 case TELEPORT:
  547.                     pain = PAIN_TELEPORT;
  548.                     slow = TRUE;
  549.                 break;
  550.                 case WOOD:
  551.                     pain = PAIN_WOOD;
  552.                     slow = TRUE;
  553.                 break;
  554.                 case BIRD:
  555.                     pain = PAIN_BIRD;
  556.                 break;
  557.                 case BOMB:
  558.                     pain = PAIN_BOMB;
  559.                 break;
  560.                 case CLOUD:
  561.                     pain = PAIN_CLOUD;
  562.                 break;
  563.                 case DOG:
  564.                     pain = PAIN_DOG;
  565.                 break;
  566.                 case FRAGMENT:
  567.                     pain = PAIN_FRAGMENT;
  568.                 break;
  569.                 case LIGHTNING:
  570.                     pain = PAIN_LIGHTNING;
  571.                 break;
  572.                 case ORB:
  573.                     pain = PAIN_ORB;
  574.                 break;
  575.                 case OTTER:
  576.                     pain = PAIN_OTTER;
  577.                 break;
  578.                 case PENGUIN:
  579.                     pain = PAIN_PENGUIN;
  580.                 break;
  581.                 case SLAYER:
  582.                     pain = PAIN_SLAYER;
  583.                 break;
  584.                 case WHIRLWIND:
  585.                     pain = PAIN_WHIRLWIND;
  586.                 break;
  587.                 default:
  588.                     // assert(0);
  589.                 break;
  590.                 }
  591.                 if (worm[player].victor >= 0 && worm[player].victor != player)
  592.                 {   if (worm[worm[player].victor].bias)
  593.                     {   worm[worm[player].victor].lives += pain;
  594.                         stat(worm[player].victor, LIFE);
  595.                 }   }
  596.                 if (slow)
  597.                 {   worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  598.                     stat(player, NITRO); 
  599.                 }
  600.                 if (pain > worm[player].lives)
  601.                     worm[player].lives = 0;
  602.                 else worm[player].lives -= pain;
  603.  
  604.                 draw(worm[player].x, worm[player].y, SKULL);
  605.                 drawcause(player, NORMAL);
  606.                 stat(player, LIFE);
  607.                 if (level)
  608.                     worm[player].levelreached = level;
  609.                 else worm[player].levelreached = reallevel;
  610.                 if (worm[player].lives)
  611.                 {   effect(FXPAIN + player);
  612.                     worm[player].alive = TRUE;
  613.                     worm[player].causewait = r + CAUSEWAIT;
  614.                 } else
  615.                 {   /* kill worm */
  616.                     effect(FXDEATH_WORM);
  617.                     field[worm[player].x][worm[player].y] = SKULL;
  618.                     updatearrow(worm[player].y);
  619.                     for (which = 0; which <= PROTECTORS; which++)
  620.                         if (protector[player][which].alive && protector[player][which].visible)
  621.                             change(protector[player][which].x, protector[player][which].y, EMPTY);
  622.                     for (which = 0; which <= MAGNETS; which++)
  623.                         if (magnet[which].player == player)
  624.                             magnet[which].alive = FALSE;
  625.                     if (worm[player].score >= worm[player].hiscore)
  626.                         worm[player].hiscore = worm[player].score;
  627.     }   }   }   }
  628.  
  629.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  630.     {   /* End of game */
  631.         for (player = 0; player <= 3; player++)
  632.             if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  633.                 worm[player].hiscore = worm[player].score;
  634.         newhiscores();
  635.         effect(FXGAMEOVER);
  636.         a = GAMEOVER;
  637.         if (players == 1)
  638.             say((STRPTR) "Game over!", worm[onlyworm(FALSE)].colour);
  639.         elif (worm[0].control && ((!worm[1].control) || worm[1].score < worm[0].score) && ((!worm[2].control) || worm[2].score < worm[0].score) && ((!worm[3].control) || worm[3].score < worm[0].score))
  640.             say((STRPTR) "Green wins!", GREEN);
  641.         elif (worm[1].control && ((!worm[0].control) || worm[0].score < worm[1].score) && ((!worm[2].control) || worm[2].score < worm[1].score) && ((!worm[3].control) || worm[3].score < worm[1].score))
  642.             say((STRPTR) "Red wins!", RED);
  643.         elif (worm[2].control && ((!worm[0].control) || worm[0].score < worm[2].score) && ((!worm[1].control) || worm[1].score < worm[2].score) && ((!worm[3].control) || worm[3].score < worm[2].score))
  644.             say((STRPTR) "Blue wins!", BLUE);
  645.         elif (worm[3].control && ((!worm[0].control) || worm[0].score < worm[3].score) && ((!worm[1].control) || worm[1].score < worm[3].score) && ((!worm[2].control) || worm[2].score < worm[3].score))
  646.             say((STRPTR) "Yellow wins!", YELLOW);
  647.         else say((STRPTR) "A draw!", WHITE);
  648.         waitasec();
  649.         anykey(FALSE);
  650. }   }
  651.  
  652. MODULE void drawcause(SBYTE player, SBYTE state)
  653. {   if (iso)
  654.     {   if (state == BLACK)
  655.         {   draw
  656.             (   -10,
  657.                 (FIELDY / 2) - 9 + player,
  658.                 BLACKENED
  659.             );
  660.         } else
  661.         {   draw
  662.             (   -10,
  663.                 (FIELDY / 2) - 9 + player,
  664.                 worm[player].cause
  665.             );
  666.     }   }
  667.     else
  668.     {   if (state == BLACK)
  669.         {   draw
  670.             (   -2 + ((FIELDX + 5) * worm[player].statx),
  671.                 (FIELDY / 2) - 4 + (worm[player].staty * 7),
  672.                 BLACKENED
  673.             );
  674.         } else
  675.         {   draw
  676.             (   -2 + ((FIELDX + 5) * worm[player].statx),
  677.                 (FIELDY / 2) - 4 + (worm[player].staty * 7),
  678.                 worm[player].cause
  679.             );
  680. }   }   }
  681.  
  682. MODULE void drawletter(SBYTE letter, SBYTE state)
  683. {   UBYTE c;
  684.     
  685.     if (state == BLACK)
  686.         c = BLACKENED;
  687.     else c = letter;
  688.     if (iso)
  689.     {   draw(-9 + (letter - FIRSTLETTER), FIELDY / 2 - 4, c);
  690.     } else
  691.     {   draw(-9 + (letter - FIRSTLETTER), FIELDY / 2,     c);
  692. }   }
  693.  
  694. /* NAME     enginesetup -- once-only initialization of engine variables
  695. SYNOPSIS    enginesetup(void);
  696. FUNCTION    Sets up the unchanging worm variables.
  697. MODULE      engine.c */
  698.  
  699. void enginesetup(void)
  700. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  701.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  702.     worm[0].colour = GREEN;
  703.     worm[1].colour = RED;
  704.     worm[2].colour = BLUE;
  705.     worm[3].colour = YELLOW;
  706.     worm[0].port = 2;
  707.     worm[1].port = 3;
  708.     worm[2].port = 1;
  709.     worm[3].port = 0;
  710.     worm[0].name[0] = worm[1].name[0] = worm[2].name[0] = worm[3].name[0] = 0;
  711.     worm[0].dynamitescore =
  712.     worm[1].dynamitescore =
  713.     worm[2].dynamitescore =
  714.     worm[3].dynamitescore = 0;
  715.  
  716.     strcpy(pathname, DEFAULTSET);
  717.  
  718.     systemsetup();
  719. }
  720.  
  721. /* NAME    fastloop -- things done often
  722. SYNOPSIS   fastloop(void);
  723. FUNCTION   Checks for and handles level completion.
  724. MODULE     engine.c */
  725.  
  726. MODULE void fastloop(void)
  727. {   AUTO ABOOL complete   = TRUE;
  728.     AUTO SBYTE advancer, i, player, which, x, y;
  729.     AUTO UWORD counter[4] = {0, 0, 0, 0};
  730.  
  731.     // all octopi spin together, but some may not be spinning, each may
  732.     // be in a different part of its spin.
  733.     if (!arand(FREQ_OCTOPUSSPIN))
  734.     {   for (i = 0; i <= CREATURES; i++)
  735.         {   if (creature[i].alive && creature[i].species == OCTOPUS && creature[i].dir >= 0)
  736.             {   octopusfire(i);
  737.     }   }   }
  738.  
  739.     // animate
  740.     if (anims)
  741.     {   for (i = 0; i <= CREATURES; i++)
  742.         {   if (creature[i].alive && creature[i].visible)
  743.             {   if (creature[i].species == BIRD)
  744.                 {   if (!(r % 3))
  745.                     {   creature[i].frame += creature[i].dir;
  746.                         draw(creature[i].x, creature[i].y, BIRD + creature[i].frame);
  747.                         if (creature[i].frame == 0)
  748.                         {   creature[i].dir = 1;
  749.                         } elif (creature[i].frame == 2)
  750.                         {   creature[i].dir = -1;
  751.                 }   }   }
  752.                 elif (creature[i].species == MISSILE)
  753.                 {   if (!(r % 3))
  754.                     {   drawmissile(creature[i].x, creature[i].y, i);
  755.                         if (++creature[i].frame > MISSILEFRAMES)
  756.                         {   creature[i].frame = 0;
  757.     }   }   }   }   }   }
  758.  
  759.     if (banging)
  760.     {   banging = FALSE;
  761.         for (x = 0; x <= FIELDX; x++)
  762.             for (y = 0; y <= FIELDY; y++)
  763.                 if (field[x][y] == BANGDYNAMITE)
  764.                 {   change(x, y, SILVER);
  765.                     bangdynamite(x, y, infector[x][y]);
  766.                 }
  767.         for (i = 0; i <= 3; i++)
  768.             if (worm[i].dynamitescore)
  769.             {   wormscore(i, worm[i].dynamitescore);
  770.                 worm[i].dynamitescore = 0;
  771.             }
  772.         for (x = 0; x <= FIELDX; x++)
  773.             for (y = 0; y <= FIELDY; y++)
  774.                 if (field[x][y] == TEMPBANGDYNAMITE)
  775.                 {   banging = TRUE;
  776.                     field[x][y] = BANGDYNAMITE;
  777.     }           }
  778.  
  779.     /* DYNAMITE PHILOSOPHY:
  780.  
  781.     Worm gets dynamite. Instantly the dynamite infects the surrounding
  782.     dynamite into bang-dynamite.
  783.         Each fastloop, you scan the field for bang-dynamite. For each
  784.     piece you find, it turns to silver and infects any surrounding dynamite.
  785.  
  786.     flash letter */
  787.     if (level)
  788.     {   if (r % 8 == 1)
  789.             draw(letterx, lettery, WHITENED);
  790.         elif (r % 8 == 2)
  791.             draw(letterx, lettery, lettertype);
  792.     }
  793.  
  794.     // flash icons
  795.     for (player = 0; player <= 3; player++)
  796.     {   icon(player, FREEDOM);
  797.         icon(player, CUTTER);
  798.     }
  799.  
  800.     /* handle level completion */
  801.     for (which = 0; which <= LETTERS; which++)
  802.     {   if (!letters[which])
  803.         {   complete = FALSE;
  804.             break;
  805.     }   }
  806.     if (complete)
  807.     {   for (player = 0; player <= 3; player++)
  808.         {   if (worm[player].lives)
  809.             {   for (x = 0; x <= FIELDX; x++)
  810.                 {   for (y = 0; y <= FIELDY; y++)
  811.                     {   if (field[x][y] == FIRSTTAIL + player || field[x][y] == FIRSTFIRE + player)
  812.                         {   counter[player]++;
  813.         }   }   }   }   }
  814.         if (counter[0] >= counter[1]
  815.          && counter[0] >= counter[2]
  816.          && counter[0] >= counter[3])
  817.         {   advancer = 0;
  818.         } elif (counter[1] >= counter[0]
  819.          && counter[1] >= counter[2]
  820.          && counter[1] >= counter[3])
  821.         {   advancer = 1;
  822.         } elif (counter[2] >= counter[0]
  823.          && counter[2] >= counter[1]
  824.          && counter[2] >= counter[3])
  825.         {   advancer = 2;
  826.         } else
  827.         {   advancer = 3;
  828.         }
  829.  
  830.         if (level++ == 0)
  831.         {   level = reallevel + 1;
  832.             reallevel = 0;
  833.         }
  834.         stopfx();
  835.         if (level > levels)
  836.             effect(FXCELEBRATE);
  837.         newlevel(advancer);
  838. }   }
  839.  
  840. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode)
  841. {   SBYTE count = 0, xx, yy;
  842.     UBYTE c;
  843.  
  844.     if (mode)
  845.     {   do
  846.         {   xx = arand(FIELDX);
  847.             yy = arand(FIELDY);
  848.             c  = field[xx][yy];
  849.         } while ((c != SLIME && c != WOOD && c != STONE && c != METAL && (c < FIRSTTAIL || c > LASTTAIL)) && ++count < PATIENCE);
  850.     } else
  851.     {   do
  852.         {   xx = arand(FIELDX);
  853.             yy = arand(FIELDY);
  854.             c  = field[xx][yy];
  855.         } while ((c < FIRSTEMPTY || c > LASTEMPTY) && ++count < PATIENCE);
  856.     }
  857.  
  858.     if (count < PATIENCE)
  859.     {   *x = xx;
  860.         *y = yy;
  861.         return(TRUE);
  862.     } else
  863.     {   return(FALSE);
  864. }   }
  865.  
  866. void gameloop(void)
  867. {   SBYTE i, player;
  868.  
  869.     if (a == PLAYGAME)
  870.     {   ReadGameports();
  871.         fastloop();
  872.         gameinput();
  873.     }
  874.     if (a == PLAYGAME)
  875.     {   ReadGameports();
  876.         for (player = 0; player <= 3; player++)
  877.             if (worm[player].lives && !(r % worm[player].speed))
  878.                 wormloop(player);
  879.     }
  880.     if (a == PLAYGAME)
  881.     {   ReadGameports();
  882.         for (i = 0; i <= CREATURES; i++)
  883.         {   if (creature[i].alive && !(r % creature[i].speed) && (!ice || creature[i].species == MISSILE || creature[i].species == FRAGMENT))
  884.             {   creatureloop(i);
  885.     }   }   }
  886.     if (a == PLAYGAME)
  887.     {   ReadGameports();
  888.         if (!(r % SPEED_MAGNET))
  889.         {   magnetloop();
  890.         }
  891.         death();
  892.     }
  893.     if (a == PLAYGAME)
  894.     {   ReadGameports();
  895.         if (!(r % VERYSLOW))
  896.         {   slowloop();
  897.     }   }
  898.     timing();
  899. }
  900.  
  901. MODULE void killall(void)
  902. {   UBYTE i;
  903.  
  904.     for (i = 0; i <= CREATURES; i++)
  905.         creature[i].alive = FALSE;
  906.     for (i = 0; i <= MAGNETS; i++)
  907.         magnet[i].alive = FALSE;
  908.     teleport[level][2].alive = FALSE;
  909.     teleport[level][3].alive = FALSE;
  910. }
  911.  
  912. SBYTE loadfields(STRPTR fieldname)
  913. {   SBYTE i, j, x, y;
  914.     TEXT  IOBuffer[NAMELENGTH + 1];
  915.     UBYTE ver;
  916.  
  917.     /* This routine is not entirely robust, especially regarding
  918.     failures part way through reading. Also, field data values must be
  919.     those supported by the field editor (ie. objects, and the squares
  920.     represented by F1-F8), or undefined behaviour may result. None of
  921.     this is currently checked for. Provided that the fieldset was
  922.     created with the official field editor, and the file is not
  923.     corrupt, these failures should never happen anyway.
  924.  
  925.     open file */
  926.  
  927.     // say("Opening...", WHITE);
  928.  
  929.     if (!ZOpen(fieldname, FALSE))
  930.         return 1; /* no harm done */
  931.  
  932.     /* read header */
  933.  
  934.     // say("Reading header...", WHITE);
  935.  
  936.     if (!ZRead(IOBuffer, 10))
  937.     {    ZClose();
  938.         return 2; /* no harm done */
  939.     }
  940.     if (!strcmp(IOBuffer, "FSET 6.6"))
  941.         ver = 66;
  942.     elif (!strcmp(IOBuffer, "FSET 6.3"))
  943.         ver = 63;
  944.     elif (!strcmp(IOBuffer, "FSET 6.2"))
  945.         ver = 62;
  946.     elif (!strcmp(IOBuffer, "FSET 6.0"))
  947.         ver = 60;
  948.     elif (!strcmp(IOBuffer, "FSET 5.6"))
  949.         ver = 56;
  950.     elif (!strcmp(IOBuffer, "FSET 5.5"))
  951.         ver = 55;
  952.     elif (!strcmp(IOBuffer, "FSET 5.3"))
  953.         ver = 53;
  954.     elif (!strcmp(IOBuffer, "FSET 5.1"))
  955.         ver = 51;
  956.     elif (!strcmp(IOBuffer, "FSET 5.0"))
  957.         ver = 50;
  958.     else
  959.     {   ZClose();
  960.         return 3; /* no harm done */
  961.     }
  962.     levels = IOBuffer[9];
  963.  
  964.     /* read high score table */
  965.  
  966.     // say("Reading high score table...", WHITE);
  967.  
  968.     for (i = 0; i <= HISCORES; i++)
  969.     {   if (!ZRead(IOBuffer, 6))
  970.         {    ZClose();
  971.              return 4; /* incorrect levels */
  972.         }
  973.         hiscore[i].fresh                        =  FALSE;
  974.         hiscore[i].player                       =  IOBuffer[0];
  975.         hiscore[i].level                        =  IOBuffer[1];
  976.         hiscore[i].score                        = (IOBuffer[2] * 16777216)
  977.                                                 + (IOBuffer[3] * 65536)
  978.                                                 + (IOBuffer[4] * 256)
  979.                                                 +  IOBuffer[5];
  980.  
  981.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  982.         {   ZClose();
  983.             return 5; /* incorrect levels, corrupted high scores */
  984.         }
  985.         for (j = 0; j <= NAMELENGTH; j++)
  986.         {   hiscore[i].name[j]              = IOBuffer[j];
  987.         }
  988.         if (!ZRead(IOBuffer, TIMELENGTH + 1))
  989.         {   ZClose();
  990.             return 6; /* incorrect levels, corrupted high scores */
  991.         }
  992.         for (j = 0; j <= TIMELENGTH; j++)
  993.         {   hiscore[i].time[j]      = IOBuffer[j];
  994.         }
  995.         if (!ZRead(IOBuffer, DATELENGTH + 1))
  996.         {   ZClose();
  997.             return 7; /* incorrect levels, corrupted high scores */
  998.         }
  999.         for (j = 0; j <= DATELENGTH; j++)
  1000.         {   hiscore[i].date[j]      = IOBuffer[j];
  1001.     }   }
  1002.  
  1003.     // say("Reading level data...", WHITE);
  1004.  
  1005.     /* read level data */
  1006.  
  1007.     for (i = 0; i <= levels; i++)
  1008.     {   if (!ZRead(IOBuffer, 8))
  1009.         {   ZClose();
  1010.             return 9;
  1011.             /* incorrect levels, corrupted high scores,
  1012.             incorrect startx, teleports, field data */
  1013.         }
  1014.         startx[i]            =  IOBuffer[0];
  1015.         starty[i]            =  IOBuffer[1];
  1016.         teleport[i][0].alive =  IOBuffer[2];
  1017.         teleport[i][0].x     =  IOBuffer[3];
  1018.         teleport[i][0].y     =  IOBuffer[4];
  1019.         teleport[i][1].alive =  IOBuffer[5];
  1020.         teleport[i][1].x     =  IOBuffer[6];
  1021.         teleport[i][1].y     =  IOBuffer[7];
  1022.  
  1023.         if (!ZRead((char *) &board[i][0][0], LEVELSIZE))
  1024.         {   ZClose();
  1025.             return 10;
  1026.             /* incorrect levels, corrupted high scores,
  1027.             incorrect startx, teleports, field data */
  1028.         } else
  1029.         {   if (ver <= 50)
  1030.             {   // convert from FSET 5.0 to FSET 5.1 format
  1031.                 for (x = 0; x <= FIELDX; x++)
  1032.                      for (y = 0; y <= FIELDY; y++)
  1033.                           if (board[i][x][y] >= 11)
  1034.                               board[i][x][y]++;
  1035.             }
  1036.             if (ver <= 51)
  1037.             {   // convert from FSET 5.1 to FSET 5.3 format
  1038.                 for (x = 0; x <= FIELDX; x++)
  1039.                     for (y = 0; y <= FIELDY; y++)
  1040.                         if (board[i][x][y] >= 7 && board[i][x][y] <= 63)
  1041.                             board[i][x][y]++;
  1042.             }
  1043.             if (ver <= 53)
  1044.             {   // convert from FSET 5.3 to FSET 5.5 format
  1045.                 for (x = 0; x <= FIELDX; x++)
  1046.                     for (y = 0; y <= FIELDY; y++)
  1047.                         if (board[i][x][y] >= 20)
  1048.                             board[i][x][y]++;
  1049.             }
  1050.             if (ver <= 55)
  1051.             {   // convert from FSET 5.5 to FSET 5.6 format
  1052.                 for (x = 0; x <= FIELDX; x++)
  1053.                     for (y = 0; y <= FIELDY; y++)
  1054.                         if (board[i][x][y] >= 13)
  1055.                             board[i][x][y]++;
  1056.             }
  1057.             if (ver <= 56)
  1058.             {   // convert from FSET 5.6 to FSET 6.0 format
  1059.                 for (x = 0; x <= FIELDX; x++)
  1060.                     for (y = 0; y <= FIELDY; y++)
  1061.                         if (board[i][x][y] >= 8 && board[i][x][y] <= 20)
  1062.                             board[i][x][y]++;
  1063.                         elif (board[i][x][y] >= 21)
  1064.                             board[i][x][y] += 2;
  1065.             }
  1066.             if (ver <= 60)
  1067.             {   // convert from FSET 6.0 to FSET 6.2 format
  1068.                 for (x = 0; x <= FIELDX; x++)
  1069.                     for (y = 0; y <= FIELDY; y++)
  1070.                         if (board[i][x][y] >= 7)
  1071.                             board[i][x][y]++;
  1072.             }
  1073.             if (ver <= 62)
  1074.             {   // convert from FSET 6.2 to FSET 6.3/6.6 format
  1075.                 for (x = 0; x <= FIELDX; x++)
  1076.                     for (y = 0; y <= FIELDY; y++)
  1077.                         if (board[i][x][y] >= 7)
  1078.                             board[i][x][y]++;
  1079.     }   }   }
  1080.  
  1081.     // say("Open done.", WHITE);
  1082.  
  1083.     // no need to read version string
  1084.     ZClose();
  1085.     modified = FALSE;
  1086.     return 0;
  1087. }
  1088.  
  1089. MODULE void magnetloop(void)
  1090. {   SBYTE i;
  1091.     UBYTE c;
  1092.  
  1093.     for (i = 0; i <= MAGNETS; i++)
  1094.     {   if (magnet[i].alive)
  1095.         {   // defensive programming to ensure magnet is still valid
  1096.             if (field[magnet[i].x][magnet[i].y] != magnet[i].object)
  1097.             {   magnet[i].alive = FALSE;
  1098.             } else
  1099.             {   change(magnet[i].x, magnet[i].y, EMPTY);
  1100.                 magnet[i].x += bsign(worm[magnet[i].player].x - magnet[i].x);
  1101.                 magnet[i].y += bsign(worm[magnet[i].player].y - magnet[i].y);
  1102.                 c = field[magnet[i].x][magnet[i].y];
  1103.            
  1104.                 if ((c >= FIRSTEMPTY && c <= LASTEMPTY)
  1105.                  || (c >= FIRSTTAIL  && c <= LASTTAIL))
  1106.                     change(magnet[i].x, magnet[i].y, magnet[i].object);
  1107.                 elif (c >= FIRSTHEAD && c <= LASTHEAD)
  1108.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  1109.                     wormscore(c - FIRSTHEAD, wormobject(c - FIRSTHEAD, magnet[i].x, magnet[i].y));
  1110.                     change(magnet[i].x, magnet[i].y, FIRSTHEAD + magnet[i].player); // not entirely the right head image
  1111.                 } else magnet[i].alive = FALSE;
  1112. }   }   }   }
  1113.  
  1114. AGLOBAL void matchteleports(void)
  1115. {   AUTO UWORD teleports, octopi;
  1116.     AUTO SBYTE x, y, i;
  1117.  
  1118.     say("Checking fieldset...", WHITE);
  1119.     for (i = 0; i <= levels; i++)
  1120.     {   teleports = octopi = 0;
  1121.         teleport[level][0].alive = teleport[level][1].alive = FALSE;
  1122.  
  1123.         for (y = 0; y <= FIELDY; y++)
  1124.         {   for (x = 0; x <= FIELDX; x++)
  1125.             {   if (board[level][x][y] == TELEPORT)
  1126.                 {   teleports++;
  1127.                     if (teleports <= 2)
  1128.                     {   teleport[level][teleports - 1].x = x;
  1129.                         teleport[level][teleports - 1].y = y;
  1130.                     } else
  1131.                     {   board[level][x][y] = EMPTY;
  1132.                 }   }
  1133.                 elif (board[level][x][y] == OCTOPUS)
  1134.                 {   octopi++;
  1135.                     if (octopi > OCTOPI)
  1136.                     {   board[level][x][y] = EMPTY;
  1137.         }   }   }   }
  1138.  
  1139.         if (teleports == 1)
  1140.         {   board[level][teleport[level][0].x][teleport[level][0].y] = EMPTY;
  1141.         } elif (teleports >= 2)
  1142.         {   teleport[level][0].alive = teleport[level][1].alive = TRUE;
  1143. }   }   }
  1144.  
  1145. AGLOBAL void newfield(void)
  1146. {   SBYTE x, y;
  1147.  
  1148.     teleport[level][0].alive = FALSE;
  1149.     teleport[level][1].alive = FALSE;
  1150.     startx[level] = FIELDX / 2;
  1151.     starty[level] = FIELDY / 2;
  1152.  
  1153.     if (level)
  1154.         for (x = 0; x <= FIELDX; x++)
  1155.             for (y = 0; y <= FIELDY; y++)
  1156.                 board[level][x][y] = EMPTY;
  1157.     else for (x = 0; x <= FIELDX; x++)
  1158.         for (y = 0; y <= FIELDY; y++)
  1159.             board[0][x][y] = SILVER;
  1160. }
  1161.  
  1162. void newfields(void)
  1163. {   if (verify())
  1164.     {   strcpy(pathname, DEFAULTSET);
  1165.         levels = DEFAULTLEVELS;
  1166.         modified = FALSE;
  1167.         for (level = 0; level <= levels; level++)
  1168.             newfield();
  1169.         clearhiscores();
  1170.         level = 1;
  1171.         if (a == FIELDEDIT)
  1172.         {   turborender();
  1173.             saylevel(WHITE);
  1174.         } else hiscores();
  1175. }   }
  1176.  
  1177. void newgame(void)
  1178. {   SBYTE i, player;
  1179.  
  1180.     players = 0;
  1181.     for (player = 0; player <= 3; player++)
  1182.     {   if (worm[player].control != NONE)
  1183.             players++;
  1184.         worm[player].lives = 0;
  1185.         worm[player].speed = NORMAL;
  1186.         worm[player].hiscore = 0;
  1187.     }
  1188.     for (i = 1; i <= MAXLEVELS; i++)
  1189.        randomarray[i] = FALSE;
  1190.  
  1191.     r         = -1;
  1192.     trainer   = FALSE;
  1193.     ice       = 0;
  1194.     reallevel = 0;
  1195.     level     = 1;
  1196.     a         = PLAYGAME;
  1197.     clearscreen();
  1198.     newlevel(arand(3));
  1199.     timing();
  1200. }
  1201.  
  1202. MODULE void newhiscores(void)
  1203. {   PERSIST TEXT  amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R. J. Mical", "Dave Morse"};
  1204.     AUTO    SBYTE i, j, player;
  1205.  
  1206.     datestamp();
  1207.     for (player = 0; player <= 3; player++)
  1208.         for (i = 0; i <= HISCORES; i++)
  1209.             if (worm[player].control != NONE && worm[player].score >= hiscore[i].score)
  1210.             {   /* push all worse hiscores down */
  1211.  
  1212.                 if (i < HISCORES)
  1213.                     for (j = HISCORES; j >= i + 1; j--)
  1214.                     {   hiscore[j].player     = hiscore[j - 1].player;
  1215.                         hiscore[j].level      = hiscore[j - 1].level;
  1216.                         hiscore[j].score      = hiscore[j - 1].score;
  1217.                         hiscore[j].fresh      = hiscore[j - 1].fresh;
  1218.                         strcpy(hiscore[j].name, hiscore[j - 1].name);
  1219.                         strcpy(hiscore[j].date, hiscore[j - 1].date);
  1220.                         strcpy(hiscore[j].time, hiscore[j - 1].time);
  1221.                     }
  1222.                 modified = TRUE;
  1223.                 hiscore[i].player = player;
  1224.                 hiscore[i].level  = worm[player].levelreached;
  1225.                 hiscore[i].score  = worm[player].hiscore;
  1226.                 if (worm[player].control == AMIGA)
  1227.                 {   strcpy(hiscore[i].name, amiganame[player]);
  1228.                     hiscore[i].fresh = FALSE;
  1229.                 } else
  1230.                 {   strcpy(hiscore[i].name, "(New)");
  1231.                     hiscore[i].fresh = TRUE;
  1232.                 }
  1233.                 strcpy(hiscore[i].time, times);
  1234.                 strcpy(hiscore[i].date, date);
  1235.                 break; /* vital */
  1236. }           }
  1237.  
  1238. MODULE void newlevel(UBYTE player)
  1239. {   SBYTE i, j;
  1240.     UWORD octopi = 0;
  1241.     UBYTE x, y;
  1242.  
  1243.     if (level >= 2)
  1244.         rundown(player);
  1245.     if (a == PLAYGAME)
  1246.     {   if (level > levels)
  1247.         {   for (i = 0; i <= 3; i++)
  1248.             {   if (worm[i].lives)
  1249.                     worm[i].levelreached = -1;
  1250.                 if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  1251.                     worm[player].hiscore = worm[player].score;
  1252.             }
  1253.             celebrate();
  1254.             newhiscores();
  1255.             titlescreen();
  1256.         } else
  1257.         {   saylevel(WHITE);
  1258.             for (i = 0; i <= 3; i++)
  1259.             {   if (worm[i].multi > 1)
  1260.                 {   worm[i].multi   /= 2;
  1261.                 }
  1262.                 worm[i].remnants =
  1263.                 worm[i].encloser =
  1264.                 worm[i].pusher   = FALSE;
  1265.  
  1266.             }
  1267.             killall();
  1268.             clearletters();
  1269.             changefield();
  1270.             for (x = 0; x <= FIELDX; x++)
  1271.             {   for (y = 0; y <= FIELDY; y++)
  1272.                 {   if (board[level][x][y] == OCTOPUS)
  1273.                     {   octopi++;
  1274.                         if (octopi <= OCTOPI)
  1275.                         {   for (i = 0; i <= CREATURES; i++)
  1276.                             {   if (!creature[i].alive)
  1277.                                 {   createcreature(OCTOPUS, i, x, y, 0, 0, 255);
  1278.             }   }   }   }   }   }
  1279.             for (i = 0; i <= 3; i++)
  1280.             {   worm[i].speed = NORMAL;
  1281.                 if (worm[i].lives)
  1282.                     stat(i, NITRO);
  1283.                 worm[i].moved = FALSE;
  1284.                 worm[i].x = startx[sourcelevel];
  1285.                 worm[i].y = starty[sourcelevel];
  1286.                 worm[i].arrowy = worm[i].y;
  1287.         switch(i)
  1288.         {
  1289.         case 0:
  1290.             worm[0].deltax = -1;
  1291.             worm[0].deltay = 0;
  1292.         break;
  1293.         case 1:
  1294.             worm[1].deltax = 1;
  1295.             worm[1].deltay = 0;
  1296.         break;
  1297.         case 2:
  1298.             worm[2].deltax = 0;
  1299.             worm[2].deltay = -1;
  1300.         break;
  1301.         case 3:
  1302.             worm[3].deltax = 0;
  1303.             worm[3].deltay = 1;
  1304.         break;
  1305.         default:
  1306.         break;
  1307.             }   }
  1308.             turborender();
  1309.             delay = atleast(DELAY_MAX - (level * DELAY_DEC), DELAY_MIN);
  1310.  
  1311.             if (level)
  1312.             {   secondsperlevel = SECONDSPERLEVEL;
  1313.                 putletter();
  1314.                 for (i = 0; i <= 3; i++)
  1315.                 {   if (!worm[i].lives && worm[i].control != NONE)
  1316.                     {   /* create (or resurrect) a worm */
  1317.  
  1318.                         worm[i].lives      = STARTLIVES;
  1319.                         worm[i].score      = 0;
  1320.                         worm[i].oldscore   = 0;
  1321.                         worm[i].armour     = 0;
  1322.                         worm[i].alive      = TRUE;
  1323.                         worm[i].power      = 0;
  1324.                         worm[i].bias       = 0;
  1325.                         worm[i].multi      = 1;
  1326.                         worm[i].victor     = -1;
  1327.                         worm[i].ammo       = 0;
  1328.                         worm[i].remnants   =
  1329.                         worm[i].affixer    =
  1330.                         worm[i].sideshot   =
  1331.                         worm[i].pusher     =
  1332.                         worm[i].nitro      =
  1333.                         worm[i].flashed    =
  1334.                         worm[i].encloser   =
  1335.                         worm[i].rammed     = FALSE;
  1336.                         worm[i].freedom    = 0;
  1337.                         worm[i].causewait  = (ULONG) -1;
  1338.                         worm[i].last       = FIRSTTAIL + i;
  1339.                         worm[i].pos        = -1;
  1340.                         worm[i].cutter     = 0;
  1341.                         for (j = 0; j <= PROTECTORS; j++)
  1342.                         {   protector[i][j].alive = FALSE;
  1343.                         } for (j = 0; j <= LASTOBJECT; j++)
  1344.                         {   stat(i, j);
  1345.                             turbo = FALSE;
  1346.             }   }   }   }
  1347.             for (i = 0; i <= 3; i++)
  1348.             {   icon(i, REMNANTS);
  1349.                 icon(i, AFFIXER);
  1350.                 icon(i, SIDESHOT);
  1351.                 icon(i, PUSHER);
  1352.                 icon(i, FREEDOM);
  1353.                 icon(i, CUTTER);
  1354.                 icon(i, ENCLOSER);
  1355.     }   }   }
  1356.     clearkybd();
  1357.     resettime();
  1358. }
  1359.  
  1360. /* Many creatures take advantage of shared characteristics.
  1361. 11 creature types (orbs, goats, drips, fragments, missiles, penguins,
  1362. cyclones, dogs, clouds, timebombs, octopus) use the creature structure.
  1363. Independent of it are worms, protectors, worm bullets and teleports. */
  1364.  
  1365. MODULE void creatureloop(SBYTE which)
  1366. {   ABOOL happy = FALSE;
  1367.     UBYTE bestdistance, distance, player, c, i;
  1368.     SBYTE x, y, xx, yy, xxx, yyy, frontx, fronty, rearx, reary,
  1369.           deltax, deltay;
  1370.  
  1371.     x = creature[which].x;
  1372.     y = creature[which].y;
  1373.  
  1374.     if (!valid(x, y)) // defensive programming
  1375.     {   creature[which].alive = FALSE;
  1376.         return;
  1377.  
  1378.         /* TEXT temp1[SAYLIMIT + 1], temp2[8];
  1379.  
  1380.         strcpy(temp1, "BAD CREATURE AT x: ");
  1381.         stci_d(temp2, x);
  1382.         strcat(temp1, temp2);
  1383.         strcat(temp1, ", y: ");
  1384.         stci_d(temp2, y);
  1385.         strcat(temp1, temp2);
  1386.         strcat(temp1, "!");
  1387.         say(temp1, PURPLE);
  1388.         draw(FIELDX + 1, 0, creature[which].species); // indicates which creature
  1389.         Delay(250);
  1390.         clearkybd();
  1391.         anykey(FALSE); */
  1392.     }
  1393.  
  1394.     /* decide whether and where to move */
  1395.  
  1396.     switch(creature[which].species)
  1397.     {
  1398.     case BIRD:
  1399.         if (creature[which].type == 255)
  1400.         {   bestdistance = 255;
  1401.             for (player = 0; player <= 3; player++)
  1402.             {   if (worm[player].lives && !worm[player].bias)
  1403.                 {   xx = abs(worm[player].x - x);
  1404.                     yy = abs(worm[player].y - y);
  1405.                     if (xx > yy)
  1406.                         distance = xx;
  1407.                     else distance = yy;
  1408.                     if (distance <= DISTANCE_BIRD && distance < bestdistance)
  1409.                     {   effect(FXBORN_BIRD);
  1410.                         bestdistance = distance;
  1411.                         creature[which].type = player;
  1412.         }   }   }   }
  1413.         if (creature[which].type != 255) // if swooping
  1414.         {   if (worm[creature[which].type].lives && !worm[creature[which].type].bias)
  1415.             {   creature[which].deltax = bsign(worm[creature[which].type].x - x);
  1416.                 creature[which].deltay = bsign(worm[creature[which].type].y - y);
  1417.             } else
  1418.             {   creature[which].type = 255; // return to dormancy
  1419.                 creature[which].deltax = creature[which].deltay = 0;
  1420.         }   }
  1421.     break;
  1422.     case CLOUD:
  1423.         if (creature[which].x == 0 || creature[which].x == FIELDX)
  1424.             creature[which].deltax = -creature[which].deltax;
  1425.     break;
  1426.     case OTTER:
  1427.         if (secondsleft)
  1428.         {   return;
  1429.         }
  1430.         if (creature[which].journey == OTTER_RIGHT)
  1431.         {   switch(creature[which].going)
  1432.             {
  1433.             case OTTER_DOWN:
  1434.                 if (creature[which].y == FIELDY)
  1435.                 {   if (creature[which].x == FIELDX)
  1436.                     {   creature[which].journey = OTTER_LEFT;
  1437.                         creature[which].going = OTTER_UP;
  1438.                     } else
  1439.                     {   creature[which].going = OTTER_RIGHT;
  1440.                         creature[which].then  = OTTER_UP;
  1441.                 }   }
  1442.             break;
  1443.             case OTTER_RIGHT:
  1444.                 creature[which].going = creature[which].then;
  1445.             break;
  1446.             case OTTER_UP:             
  1447.                 if (creature[which].y == 0)
  1448.                 {   if (creature[which].x == FIELDX)
  1449.                     {   creature[which].journey = OTTER_LEFT;
  1450.                         creature[which].going = OTTER_DOWN;
  1451.                     } else
  1452.                     {   creature[which].going = OTTER_RIGHT;
  1453.                         creature[which].then  = OTTER_DOWN;
  1454.                 }   }
  1455.             break;
  1456.             default:
  1457.             break;
  1458.         }   }
  1459.         else
  1460.         {   // assert(creature[which].journey == OTTER_LEFT);
  1461.             switch(creature[which].going)
  1462.             {
  1463.             case OTTER_DOWN:
  1464.                 if (creature[which].y == FIELDY)
  1465.                 {   if (creature[which].x == 0)
  1466.                     {   creature[which].journey = OTTER_RIGHT;
  1467.                         creature[which].going = OTTER_UP;
  1468.                     } else
  1469.                     {   creature[which].going = OTTER_LEFT;
  1470.                         creature[which].then  = OTTER_UP;
  1471.                 }   }
  1472.             break;
  1473.             case OTTER_LEFT:
  1474.                 creature[which].going = creature[which].then;
  1475.             break;
  1476.             case OTTER_UP:             
  1477.                 if (creature[which].y == 0)
  1478.                 {   if (creature[which].x == 0)
  1479.                     {   creature[which].journey = OTTER_RIGHT;
  1480.                         creature[which].going = OTTER_DOWN;
  1481.                     } else
  1482.                     {   creature[which].going = OTTER_LEFT;
  1483.                         creature[which].then  = OTTER_DOWN;
  1484.                 }   }
  1485.             break;
  1486.             default:
  1487.                 // assert(0);
  1488.             break;
  1489.         }   }
  1490.  
  1491.         if (creature[which].going == OTTER_RIGHT)
  1492.         {   creature[which].deltax = 1;
  1493.             creature[which].deltay = 0;
  1494.         } elif (creature[which].going == OTTER_LEFT)
  1495.         {   creature[which].deltax = -1;
  1496.             creature[which].deltay = 0;
  1497.         } elif (creature[which].going == OTTER_UP)
  1498.         {   creature[which].deltax = 0;
  1499.             creature[which].deltay = -1;
  1500.         } elif (creature[which].going == OTTER_DOWN)
  1501.         {   creature[which].deltax = 0;
  1502.             creature[which].deltay = 1;
  1503.         }
  1504.     break;
  1505.     case TIMEBOMB:
  1506.     /* decrement and explode timebombs */
  1507.         if (field[x][y] != TIMEBOMB)
  1508.             creature[which].alive = FALSE;
  1509.         else
  1510.         {   effect(FXDO_BOMB);
  1511.             creature[which].time--;
  1512.             if (creature[which].time < 0)
  1513.             {   creature[which].alive = FALSE;
  1514.                 bombblast(BOMB, 0, x, y);
  1515.                 change(x, y, EMPTY);
  1516.             } else draw(x, y, ZERO + creature[which].time);
  1517.         }
  1518.         return; // not a bug
  1519.     break;
  1520.     case DOG:
  1521.         /* remove a movement from the dog queue */
  1522.  
  1523.         if (creature[which].dormant == CHASING)
  1524.         {   if (creature[which].pos != -1)
  1525.             {   creature[which].deltax = thedogqueue[which][0].deltax;
  1526.                 creature[which].deltay = thedogqueue[which][0].deltay;
  1527.                 if (--creature[which].pos != -1)
  1528.                 {   for (i = 0; i <= creature[which].pos; i++)
  1529.                     {   thedogqueue[which][i].deltax = thedogqueue[which][i + 1].deltax;
  1530.                         thedogqueue[which][i].deltay = thedogqueue[which][i + 1].deltay;
  1531.             }   }   }
  1532.             else creature[which].alive = FALSE;
  1533.         }
  1534.     break;
  1535.     case PENGUIN:
  1536.     do
  1537.         {   xx = arand(2) - 1;
  1538.             yy = arand(2) - 1;
  1539.     } while (!valid(x + xx, y + yy));
  1540.         c = field[x + xx][y + yy];
  1541.         if (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1542.         {   creature[which].deltax = xx;
  1543.             creature[which].deltay = yy;
  1544.     } else
  1545.         {   creature[which].deltax = 0;
  1546.             creature[which].deltay = 0;
  1547.     }
  1548.     break;
  1549.     case WHIRLWIND:
  1550.         /* Whirlwinds have a slight upwards drift.
  1551.         Higher values of WEIGHT make it less buoyant. */
  1552.  
  1553.         creature[which].deltax = arand(2) - 1;
  1554.         if (!arand(WEIGHT))
  1555.             creature[which].deltay = arand(1) - 1;
  1556.         else creature[which].deltay = arand(2) - 1;
  1557.     break;
  1558.     case MISSILE:
  1559.         bestdistance = 255;
  1560.         for (player = 0; player <= 3; player++)
  1561.         {   if (creature[which].type != player && worm[player].lives && !worm[player].bias)
  1562.             {   xx = abs(worm[player].x - x);
  1563.                 yy = abs(worm[player].y - y);
  1564.                 if (xx < yy)
  1565.                     distance = xx;
  1566.                 else distance = yy;
  1567.                 if (distance < bestdistance)
  1568.                 {   bestdistance = distance;
  1569.                     creature[which].deltax = bsign(worm[player].x - x);
  1570.                     creature[which].deltay = bsign(worm[player].y - y);
  1571.             }   }
  1572.             for (i = 0; i <= CREATURES; i++)
  1573.             {   if (creature[i].alive && which != i)
  1574.                 {   if
  1575.                     (   (   creature[i].species != DRIP
  1576.                          && creature[i].species != MISSILE
  1577.                         )
  1578.                          || creature[i].type != creature[which].type
  1579.                     )
  1580.                     {   xx = abs(creature[i].x - x);
  1581.                         yy = abs(creature[i].y - y);
  1582.                         if (xx < yy)
  1583.                             distance = xx;
  1584.                         else distance = yy;
  1585.                         if (distance < bestdistance)
  1586.                         {   bestdistance = distance;
  1587.                             creature[which].deltax = bsign(creature[i].x - x);
  1588.                             creature[which].deltay = bsign(creature[i].y - y);
  1589.         }   }   }   }   }
  1590.         if (bestdistance == 255)
  1591.         {   creature[which].alive = FALSE;
  1592.             change(x, y, EMPTY);
  1593.         }
  1594.     break;
  1595.     case ORB:
  1596.         frontx  = xwrap(x + creature[which].deltax);  /* look in front */
  1597.         fronty  = ywrap(y + creature[which].deltay);
  1598.         rearx   = xwrap(x - creature[which].deltax);  /* look behind */
  1599.         reary   = ywrap(y - creature[which].deltay);
  1600.         if (bounceorb(which, frontx, fronty))
  1601.         {   bouncegoatoctopus(which, frontx, fronty);
  1602.             xx = -creature[which].deltax; /* default bounce angle is 180° */
  1603.             yy = -creature[which].deltay;
  1604.             if (!bounceorb(which, frontx, reary))
  1605.             {   if (bounceorb(which, rearx, fronty))
  1606.                 {   bouncegoatoctopus(which, rearx, fronty);
  1607.                     xx = creature[which].deltax;
  1608.             }   }
  1609.             elif (!bounceorb(which, rearx, fronty))
  1610.             {   bouncegoatoctopus(which, rearx, fronty);
  1611.                 yy = creature[which].deltay;
  1612.             }
  1613.             creature[which].deltax = xx;
  1614.             creature[which].deltay = yy;
  1615.         }
  1616.     break;
  1617.     case FISH:
  1618.     do
  1619.         {   xx = arand(2) - 1;
  1620.             yy = arand(2) - 1;
  1621.     } while (!valid(x + xx, y + yy));
  1622.         c = field[x + xx][y + yy];
  1623.         if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
  1624.         {   creature[which].deltax = xx;
  1625.             creature[which].deltay = yy;
  1626.             creature[which].last = creature[which].oldlast;
  1627.             if (c >= FIRSTTAIL && c <= LASTTAIL)
  1628.             {   creature[which].oldlast = c - FIRSTTAIL + FIRSTFIRE;
  1629.             } else creature[which].oldlast = c;    
  1630.         } else
  1631.         {   creature[which].deltax =
  1632.             creature[which].deltay = 0;
  1633.         }
  1634.     break;
  1635.     case GOAT:
  1636.         /* decide whether to move */
  1637.         if (!arand(FREQ_GOATMOVE))
  1638.         {   for (xx = x - 1; xx <= x + 1; xx++)
  1639.             {   for (yy = y - 1; yy <= y + 1; yy++)
  1640.                 {   if (valid(xx, yy) && field[xx][yy] >= FIRSTEMPTY && field[xx][yy] <= LASTEMPTY)
  1641.                     {   happy = TRUE;
  1642.                         break;
  1643.         }   }   }   }
  1644.         creature[which].deltax =
  1645.         creature[which].deltay = 0;
  1646.         if (!happy)
  1647.         {   xx = arand(2) - 1;
  1648.             yy = arand(2) - 1;
  1649.             if (valid(x + xx, y + yy) && (xx || yy))
  1650.             {   c = field[x + xx][y + yy];
  1651.                 if (c == SLIME || c == WOOD || c == STONE || c == METAL || (c >= FIRSTTAIL && c <= LASTTAIL))
  1652.                 {   creature[which].last = creature[which].oldlast;
  1653.                     creature[which].oldlast = c;
  1654.                     creature[which].deltax = xx;
  1655.                     creature[which].deltay = yy;
  1656.         }   }   }
  1657.     break;
  1658.     default:
  1659.     break;
  1660.     }
  1661.  
  1662.     /* now move */
  1663.  
  1664.     if (creature[which].deltax || creature[which].deltay)
  1665.     {   if (creature[which].visible)
  1666.     {   /* erase previous image */
  1667.             change(x, y, creature[which].last);
  1668.             if (creature[which].species == OTTER)
  1669.             {   if ((worm[0].lives && worm[0].bias)
  1670.                  || (worm[1].lives && worm[1].bias)
  1671.                  || (worm[2].lives && worm[2].bias)
  1672.                  || (worm[3].lives && worm[3].bias))
  1673.                  {   creature[which].last = DYNAMITE;
  1674.                  } else creature[which].last = STONE;
  1675.             } else
  1676.             {   creature[which].last = EMPTY;
  1677.         }   }
  1678.     if (creature[which].alive)
  1679.     {   creature[which].x += creature[which].deltax;
  1680.         creature[which].y += creature[which].deltay;
  1681.         if (creature[which].species == ORB)
  1682.         {   creature[which].x = xwrap(creature[which].x);
  1683.             creature[which].y = ywrap(creature[which].y);
  1684.             } elif
  1685.             (   creature[which].species == DOG
  1686.              || creature[which].species == DRIP
  1687.              || creature[which].species == FRAGMENT
  1688.              || creature[which].species == WHIRLWIND
  1689.             )
  1690.         {    if (!valid(creature[which].x, creature[which].y))
  1691.                 {   creature[which].alive = FALSE;
  1692.     }   }   }   }
  1693.  
  1694.     creature[which].visible = TRUE;
  1695.     x = creature[which].x;
  1696.     y = creature[which].y;
  1697.  
  1698.     /* Collision detection. */
  1699.  
  1700.     if
  1701.     (    creature[which].alive
  1702.      &&  creature[which].species != FISH
  1703.      &&  creature[which].species != GOAT
  1704.      &&  creature[which].species != PENGUIN
  1705.      &&  creature[which].species != OCTOPUS
  1706.      &&  creature[which].species != TIMEBOMB
  1707.      && (creature[which].deltax || creature[which].deltay)
  1708.     )
  1709.     {   c = field[x][y];
  1710.  
  1711.         if (c >= FIRSTHEAD && c <= LASTHEAD)
  1712.         {   wormcreature(c - FIRSTHEAD, which);
  1713.         } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  1714.         {   protcreature(c - FIRSTPROTECTOR, which);
  1715.         } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  1716.         {   ;
  1717.         } elif (c >= FIRSTLETTER && c <= LASTLETTER)
  1718.         {   if (creature[which].species == ORB)
  1719.             {   letters[c - FIRSTLETTER] = FALSE;
  1720.                 drawletter(c, BLACK);
  1721.                 putletter();
  1722.             } elif (creature[which].species == OTTER)
  1723.             {   putletter();
  1724.             } else
  1725.             {   creature[which].alive = FALSE;
  1726.         }   }
  1727.         elif (c == TIMEBOMB)
  1728.         {   if (creature[which].species != OTTER)
  1729.             {   creature[whichcreature(x, y, TIMEBOMB, which)].alive = FALSE;
  1730.             }
  1731.             bombblast(BOMB, 0, x, y);
  1732.             change(x, y, EMPTY);
  1733.         } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  1734.         {   i = whichcreature(x, y, DRIP, which);
  1735.             creaturecreature(i, which);
  1736.         } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  1737.         {   i = whichcreature(x, y, MISSILE, which);
  1738.             creaturecreature(which, i);
  1739.         } elif
  1740.         (   c == BIRD
  1741.          || c == DOG
  1742.          || c == CLOUD
  1743.          || c == FISH
  1744.          || c == FRAGMENT
  1745.          || c == GOAT
  1746.          || c == OCTOPUS
  1747.          || c == ORB
  1748.          || c == OTTER
  1749.          || c == PENGUIN
  1750.          || c == WHIRLWIND
  1751.         )
  1752.         {   i = whichcreature(x, y, c, which);
  1753.             creaturecreature(which, i);
  1754.         } elif (c == METAL)
  1755.         {   if (creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1756.                 creature[which].alive = FALSE;
  1757.             elif (creature[which].species == FRAGMENT)
  1758.                 reflect(which);
  1759.         } elif (c == STONE)
  1760.         {   if (creature[which].species == DRIP || creature[which].species == FRAGMENT || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1761.             {   effect(FXDEATH_FRAGMENT);
  1762.                 creature[which].alive = FALSE;
  1763.         }   }
  1764.         elif (c == WOOD)
  1765.         {   if (creature[which].species == FRAGMENT || creature[which].species == MISSILE || creature[which].species == CLOUD || creature[which].species == DRIP)
  1766.             {   effect(FXDEATH_FRAGMENT);
  1767.                 creature[which].alive = FALSE;
  1768.         }   }
  1769.         elif (c == DYNAMITE)
  1770.         {   ;
  1771.         } elif (c == SKULL)
  1772.         {   if (creature[which].species == ORB)
  1773.             {   effect(FXGET_SKULL);
  1774.             } elif (creature[which].species == FRAGMENT || creature[which].species == DRIP || creature[which].species == MISSILE || creature[which].species == CLOUD)
  1775.             {   effect(FXDEATH_FRAGMENT);
  1776.                 creature[which].alive = FALSE;
  1777.         }   }
  1778.         elif (c == TELEPORT)
  1779.         {   /* Drips, fragments, missiles, orbs, whirlwinds, dogs, clouds, otters */
  1780.             i = whichteleport(x, y);
  1781.             if (creature[which].species != OTTER && blocked(i, creature[which].deltax, creature[which].deltay))
  1782.                 creature[which].alive = FALSE;
  1783.             else
  1784.             {   effect(FXUSE_TELEPORT);
  1785.                 creature[which].x = teleport[level][partner(i)].x + creature[which].deltax;
  1786.                 creature[which].y = teleport[level][partner(i)].y + creature[which].deltay;
  1787.  
  1788.                 if (creature[which].species == ORB)
  1789.                 {   creature[which].x = xwrap(creature[which].x);
  1790.                     creature[which].y = ywrap(creature[which].y);
  1791.                 } else
  1792.                 {   if (!(valid(creature[which].x, creature[which].y)))
  1793.                         creature[which].alive = FALSE;
  1794.                     if (creature[which].species == FRAGMENT)
  1795.                         creature[which].last = SILVER;
  1796.         }   }   }
  1797.         elif (creature[which].species == ORB)
  1798.         {   if (c <= LASTOBJECT)
  1799.             {   if
  1800.                 (   c == AMMO
  1801.                  || c == CYCLONE
  1802.                  || c == LIGHTNING
  1803.                  || c == NITRO
  1804.                  || c == POWER
  1805.                  || c == PULSE
  1806.                  || c == SLAYER
  1807.                  || c == SLOWER
  1808.                  || c == ENCLOSER
  1809.                 )
  1810.                 {   effect(FXGET_NITRO);
  1811.                     creature[which].speed = speedup(creature[which].speed, TRUE);
  1812.                 } elif (c == HEALER || c == LIFE || c == ICE || c == TREASURE || c == UMBRELLA || c == BONUS || c == ARMOUR)
  1813.                 {   orbsplit(which);
  1814.                 } else switch (c)
  1815.                 {
  1816.                 case BOMB:
  1817.                     draw(x, y, ORB);
  1818.                     bombblast(ORB, which, x, y);
  1819.                 break;
  1820.                 case PROTECTOR:
  1821.                     for (player = 0; player <= 3; player++)
  1822.                     {   if (worm[player].lives)
  1823.                         {   for (i = 0; i <= PROTECTORS; i++)
  1824.                             {  if (protector[player][i].alive)
  1825.                                {   protector[player][i].alive = FALSE;
  1826.                                    if (protector[player][i].visible)
  1827.                                    {   change(protector[player][i].x, protector[player][i].y, EMPTY);
  1828.                     }   }   }  }   }
  1829.                 break;
  1830.                 case MISSILE:
  1831.                 case CONVERTER:
  1832.                     effect(FXGET_OBJECT);
  1833.                     for (i = 0; i <= CREATURES; i++)
  1834.                     {   if (creature[i].alive && creature[i].species == MISSILE)
  1835.                         {   creature[i].alive = FALSE;
  1836.                             change(x, y, EMPTY);
  1837.                     }   }
  1838.                 break;
  1839.                 case MULTIPLIER:
  1840.                     effect(FXGET_OBJECT);
  1841.                     creature[which].multi *= 2;
  1842.                     if (creature[which].multi > MULTILIMIT)
  1843.                         creature[which].multi = MULTILIMIT;
  1844.                 break;
  1845.                 case BIAS:
  1846.                     effect(FXGET_OBJECT);
  1847.                     for (player = 0; player <= 3; player++)
  1848.                         if (worm[player].lives && worm[player].bias)
  1849.                         {   worm[player].bias = 0;
  1850.                             stat(player, BIAS);
  1851.                         }
  1852.                 break;
  1853.                 case AFFIXER:
  1854.                     effect(FXGET_OBJECT);
  1855.                     for (player = 0; player <= 3; player++)
  1856.                         if (worm[player].lives)
  1857.                         {   worm[player].affixer = FALSE;
  1858.                             icon(player, AFFIXER);
  1859.                         }
  1860.                 break;
  1861.                 case REMNANTS:
  1862.                     effect(FXGET_OBJECT);
  1863.                     for (player = 0; player <= 3; player++)
  1864.                         if (worm[player].lives)
  1865.                         {   worm[player].remnants = FALSE;
  1866.                             icon(player, REMNANTS);
  1867.                         }
  1868.                 break;
  1869.                 case SIDESHOT:
  1870.                     effect(FXGET_POWERUP);
  1871.                     for (player = 0; player <= 3; player++)
  1872.                         if (worm[player].lives)
  1873.                         {   worm[player].sideshot = FALSE;
  1874.                             icon(player, SIDESHOT);
  1875.                         }
  1876.                 break;
  1877.                 case MAGNET:
  1878.                     effect(FXGET_OBJECT);
  1879.                     for (i = 0; i <= MAGNETS; i++)
  1880.                         if (magnet[i].alive)
  1881.                             magnet[i].alive = FALSE;
  1882.                 break;
  1883.                 case PUSHER:
  1884.                     effect(FXGET_OBJECT);
  1885.                     for (i = 0; i <= 3; i++)
  1886.                         if (worm[i].lives && worm[i].pusher)
  1887.                         {   worm[i].pusher = FALSE;
  1888.                             icon(i, PUSHER);
  1889.                         }
  1890.                 break;
  1891.                 case FREEDOM:
  1892.                     effect(FXGET_OBJECT);
  1893.                     for (xx = 0; xx <= FIELDX; xx++)
  1894.                         for (yy = 0; yy <= FIELDY; yy++)
  1895.                             if (field[xx][yy] >= FIRSTFIRE && field[xx][yy] <= LASTFIRE)
  1896.                                 change(xx, yy, EMPTY);
  1897.                 break;
  1898.                 case SWITCHER:
  1899.                     effect(FXGET_OBJECT);
  1900.                     for (xx = 0; xx <= FIELDX; xx++)
  1901.                         for (yy = 0; yy <= FIELDY; yy++)
  1902.                             if (field[xx][yy] >= FIRSTTAIL && field[xx][yy] <= LASTTAIL)
  1903.                                 change(xx, yy, WOOD);
  1904.                 break;
  1905.                 case GROWER:
  1906.                     effect(FXGET_GROWER);
  1907.                     for (xx = 0; xx <= FIELDX; xx++)
  1908.                         for (yy = 0; yy <= FIELDY; yy++)
  1909.                             if (field[xx][yy] == WOOD)
  1910.                                 for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  1911.                                     for (yyy = yy - 1; yyy <= yy + 1; yyy++)                                                                if (valid(xxx, yyy) && field[xxx][yyy] == EMPTY)
  1912.                                         field[xxx][yyy] = TEMPWOOD;
  1913.                     for (xx = 0; xx <= FIELDX; xx++)
  1914.                         for (yy = 0; yy <= FIELDY; yy++)
  1915.                             if (field[xx][yy] == TEMPWOOD)
  1916.                                 change(xx, yy, WOOD);
  1917.                 break;
  1918.                 case CLOCK:
  1919.                     secondsperlevel -= arand(RAND_CLOCK);
  1920.                     if (secondsperlevel < 0)
  1921.                         secondsperlevel = 0;
  1922.                 break;
  1923.                 case CUTTER:
  1924.                     for (i = 0; i <= 3; i++)
  1925.                         if (worm[i].lives && worm[i].cutter)
  1926.                         {   worm[i].cutter = 0;
  1927.                             icon(i, CUTTER);
  1928.                         }
  1929.                 break;
  1930.                 default:
  1931.                     // assert(0);
  1932.                 break;
  1933.     }   }   }   }
  1934.     
  1935.     x = creature[which].x; /* We refresh these in case a fragment has been */
  1936.     y = creature[which].y; /* reflected. Yes, it is vital. */
  1937.         
  1938.     if (creature[which].alive && creature[which].visible && (creature[which].deltax || creature[which].deltay))
  1939.     {   if (creature[which].species == MISSILE)
  1940.         {   drawmissile(x, y, which);
  1941.         } elif (creature[which].species == DRIP)
  1942.         {   change(x, y, FIRSTDRIP + creature[which].type);
  1943.         } else /* fragments, goats, penguins, cyclones, dogs, clouds, orbs, octopi, fish, otters */
  1944.         {   change(x, y, creature[which].species);
  1945.     }   }
  1946.     
  1947.     if (creature[which].alive)
  1948.     {   /* decide whether to fire */
  1949.         if (creature[which].species == GOAT)
  1950.         {   if (!arand(FREQ_GOATFIRE))
  1951.             {   for (i = 0; i <= CREATURES; i++)
  1952.                 {   if (!creature[i].alive)
  1953.                     {   deltax = arand(2) - 1;
  1954.                         deltay = arand(2) - 1;
  1955.                         if (valid(x + deltax, y + deltay) && (deltax || deltay))
  1956.                         {   c = field[x + deltax][y + deltay];
  1957.                             if
  1958.                             (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1959.                              || (c >= FIRSTTAIL && c <= LASTTAIL)
  1960.                             )
  1961.                             {   effect(FXDO_GOAT);
  1962.                                 createcreature(FRAGMENT, i, x + deltax, y + deltay, deltax, deltay, 255);
  1963.                         }   }
  1964.                         break;
  1965.         }   }   }   }
  1966.         elif (creature[which].species == CLOUD)
  1967.         {   if (!arand(FREQ_CLOUDFIRE))
  1968.             {   cloudbullet(which, x, y, -1);
  1969.                 cloudbullet(which, x, y, 1);
  1970.         }   }
  1971.         elif (creature[which].species == OCTOPUS)
  1972.         {   if (creature[which].dir == -1)
  1973.             {   if (!arand(FREQ_OCTOPUSFIRE))
  1974.                 {   creature[which].dir = 0;
  1975. }   }   }   }   }
  1976.  
  1977. MODULE void cloudbullet(UBYTE which, SBYTE x, SBYTE y, SBYTE deltay)
  1978. {   UBYTE i, c;
  1979.  
  1980.     for (i = 0; i <= CREATURES; i++)
  1981.     {   if (!creature[i].alive)
  1982.         {   if (valid(x, y + deltay))
  1983.             {   c = field[x][y + deltay];
  1984.                 if
  1985.                 (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1986.                 ||  (c >= FIRSTTAIL && c <= LASTTAIL)
  1987.                 )
  1988.                 {   effect(FXDO_CLOUD);
  1989.                     createcreature(FRAGMENT, i, x, y + deltay, 0, deltay, 255);
  1990.             }   }
  1991.             break;
  1992. }   }   }
  1993.  
  1994. MODULE void orbsplit(SBYTE which)
  1995. {   SBYTE copy = 0, i;
  1996.  
  1997.     effect(FXDO_ORB);
  1998.     for (i = 0; i <= CREATURES; i++)
  1999.     {   if (!creature[i].alive)
  2000.         {   creature[i].x       = creature[which].x;
  2001.             creature[i].y       = creature[which].y;
  2002.             creature[i].score   = creature[which].score;
  2003.             creature[i].speed   = creature[which].speed;
  2004.             creature[i].multi   = creature[which].multi;
  2005.             creature[i].last    = EMPTY;
  2006.             creature[i].species = ORB;
  2007.             switch (copy)
  2008.             {
  2009.             case 0:
  2010.                 if (creature[which].deltax != -1 || creature[which].deltay != -1)
  2011.                 {   creature[i].deltax = -1;
  2012.                     creature[i].deltay = -1;
  2013.                     creature[i].alive = TRUE;
  2014.                 }
  2015.             break;
  2016.             case 1:
  2017.                 if (creature[which].deltax != 1 || creature[which].deltay != 1)
  2018.                 {   creature[i].deltax = 1;
  2019.                     creature[i].deltay = 1;
  2020.                     creature[i].alive = TRUE;
  2021.                 }
  2022.             break;
  2023.             case 2:
  2024.                 if (creature[which].deltax != 1 || creature[which].deltay != -1)
  2025.                 {   creature[i].deltax = 1;
  2026.                     creature[i].deltay = -1;
  2027.                     creature[i].alive = TRUE;
  2028.                 }
  2029.             break;
  2030.             case 3:
  2031.                 if (creature[which].deltax != -1 || creature[which].deltay != 1)
  2032.                 {   creature[i].deltax = -1;
  2033.                     creature[i].deltay = 1;
  2034.                     creature[i].alive = TRUE;
  2035.                 }
  2036.             break;
  2037.             default:
  2038.             break;
  2039.             }
  2040.             if (++copy >= 4)
  2041.                 return;
  2042. }   }   }
  2043.  
  2044. SBYTE partner(SBYTE which)
  2045. {   if (which % 2 == 0)
  2046.         return((SBYTE) (which + 1));
  2047.     else return((SBYTE) (which - 1));
  2048. }
  2049.  
  2050. /* NAME     putletter -- Put a letter onto the field
  2051. SYNOPSIS    void putletter(void);
  2052. INPUTS      none
  2053. RESULT      none */
  2054.  
  2055. MODULE void putletter(void)
  2056. {   ABOOL done;
  2057.     SBYTE i, x, y;
  2058.     UBYTE letter;
  2059.     SBYTE oldlettery = lettery;
  2060.  
  2061.     do
  2062.     {   done = findempty(&x, &y, FALSE);
  2063.     } while (!done);
  2064.     for (i = 0; i <= LETTERS; i++)
  2065.     {   if (!letters[i])
  2066.         {   break;
  2067.     }   }
  2068.     if (i > LETTERS) /* if no spare letters */
  2069.     {   letter = arand(LETTERS);
  2070.     } else
  2071.     {   do
  2072.         {   letter = arand(LETTERS);
  2073.         } while (letters[letter]);
  2074.     }
  2075.  
  2076.     change(x, y, letter + FIRSTLETTER);
  2077.     letterx = x;
  2078.     lettery = y;
  2079.     lettertype = letter + FIRSTLETTER;
  2080.     updatearrow(oldlettery);
  2081.     updatearrow(lettery);
  2082. }
  2083.  
  2084. /* NAME     queue -- adds a keystroke to the key queue
  2085. SYNOPSIS    name(SBYTE, SBYTE, SBYTE);
  2086. FUNCTION    Adds a keystroke to the in-game key queue.
  2087. INPUTS      player - player that pressed the key
  2088.             deltax - the deltax of the key
  2089.             deltay - the deltay of the key
  2090. IMPLEMENTATION
  2091.             thewormqueue[] array has WORMQUEUELIMIT as its last index.
  2092.             It is implemented as a FIFO stack rather than LIFO so that
  2093.             the keystrokes are processed in the correct order (that is,
  2094.             the order in which they were pressed). The oldest keystroke
  2095.             is always at index [0], the next oldest at [1], and so on
  2096.             upwards to the newest keystroke, at [worm[player].pos].
  2097.             Keystrokes are removed from the bottom of the array ([0]),
  2098.             and the rest of the array is shuffled down to fill the gap,
  2099.             so that the contents of [1] go to [0], the contents of [2]
  2100.             go to [1], etc. worm[player].pos is adjusted to always point
  2101.             to the newest entry, which is the 'end' of the queue.
  2102. MODULE      engine.c */
  2103.  
  2104. void wormqueue(SBYTE player, SBYTE deltax, SBYTE deltay)
  2105. {   if (worm[player].pos < WORMQUEUELIMIT)
  2106.     {   worm[player].pos++;
  2107.         thewormqueue[player][worm[player].pos].deltax = deltax;
  2108.         thewormqueue[player][worm[player].pos].deltay = deltay;
  2109. }   }
  2110.  
  2111. MODULE void dogqueue(SBYTE which, SBYTE deltax, SBYTE deltay)
  2112. {   if (creature[which].pos < DOGQUEUELIMIT)
  2113.     {   creature[which].pos++;
  2114.         thedogqueue[which][creature[which].pos].deltax = deltax;
  2115.         thedogqueue[which][creature[which].pos].deltay = deltay;
  2116.     } else
  2117.     {   creature[which].alive = FALSE;
  2118.         change(creature[which].x, creature[which].y, EMPTY);
  2119. }   }
  2120.  
  2121. MODULE void reflect(UBYTE which)
  2122. {   creature[which].deltax  = -creature[which].deltax;
  2123.     creature[which].deltay  = -creature[which].deltay;
  2124.     creature[which].x      +=  creature[which].deltax * 2;
  2125.     creature[which].y      +=  creature[which].deltay * 2;
  2126. }
  2127.  
  2128. ABOOL savefields(STRPTR fieldname)
  2129. {   SBYTE i, j;
  2130.     TEXT  IOBuffer[NAMELENGTH + 1];
  2131.  
  2132.     matchteleports();
  2133.  
  2134.     if (!ZOpen(fieldname, TRUE))
  2135.         return FALSE;
  2136.  
  2137.     /* write header */
  2138.  
  2139.     strcpy(IOBuffer, "FSET 6.6");
  2140.     IOBuffer[9] = levels;
  2141.     if (!ZWrite(IOBuffer, 10))
  2142.     {   ZClose();
  2143.         return FALSE;
  2144.     }
  2145.  
  2146.     /* write high score table */
  2147.  
  2148.     for (i = 0; i <= HISCORES; i++)
  2149.     {   IOBuffer[0]                                             =  hiscore[i].player;
  2150.         IOBuffer[1]                                             =  hiscore[i].level;
  2151.  
  2152.         IOBuffer[2]                                             =   hiscore[i].score / 16777216;
  2153.         IOBuffer[3]                                             =  (hiscore[i].score % 16777216) / 65536;
  2154.         IOBuffer[4]                                             = ((hiscore[i].score % 16777216) % 65536) / 256;
  2155.         IOBuffer[5]                                             = ((hiscore[i].score % 16777216) % 65536) % 256;
  2156.         if (!ZWrite(IOBuffer, 6))
  2157.         {   ZClose();
  2158.             return FALSE;
  2159.         }
  2160.  
  2161.         for (j = 0; j <= NAMELENGTH; j++)
  2162.             IOBuffer[j]                                             = hiscore[i].name[j];
  2163.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  2164.         {   ZClose();
  2165.             return FALSE;
  2166.         }
  2167.         for (j = 0; j <= TIMELENGTH; j++)
  2168.             IOBuffer[j]                                             = hiscore[i].time[j];
  2169.         if (!ZWrite(IOBuffer, TIMELENGTH + 1))
  2170.         {   ZClose();
  2171.             return FALSE;
  2172.         }
  2173.         for (j = 0; j <= DATELENGTH; j++)
  2174.             IOBuffer[j]                                             = hiscore[i].date[j];
  2175.         if (!ZWrite(IOBuffer, DATELENGTH + 1))
  2176.         {   ZClose();
  2177.             return FALSE;
  2178.     }   }
  2179.  
  2180.     /* write level data */
  2181.  
  2182.     for (i = 0; i <= levels; i++)
  2183.     {   IOBuffer[0]                        = startx[i];
  2184.         IOBuffer[1]                        = starty[i];
  2185.         IOBuffer[2]                                             = teleport[i][0].alive;
  2186.         IOBuffer[3]                                             = teleport[i][0].x;
  2187.         IOBuffer[4]                                             = teleport[i][0].y;
  2188.         IOBuffer[5]                                             = teleport[i][1].alive;
  2189.         IOBuffer[6]                                             = teleport[i][1].x;
  2190.         IOBuffer[7]                                             = teleport[i][1].y;
  2191.         if (!ZWrite(IOBuffer, 8))
  2192.         {   ZClose();
  2193.             return FALSE;
  2194.         }
  2195.  
  2196.         if (!ZWrite((char *) &board[i][0][0], LEVELSIZE))
  2197.         {   ZClose();
  2198.             return FALSE;
  2199.     }   }
  2200.  
  2201.     /* write version string */
  2202.  
  2203.     if (!ZWrite(VERSION, strlen(VERSION)))
  2204.     {   ZClose();
  2205.         return FALSE;
  2206.     }
  2207.  
  2208.     ZClose();
  2209.  
  2210.     if (clearthem)
  2211.         clearhiscores();
  2212.     modified = FALSE;
  2213.     return TRUE;
  2214. }
  2215.  
  2216. void saylevel(COLOUR colour)
  2217. {    TEXT mainstring[15] = "Level ", tempstring[4];
  2218.  
  2219.     if (level > 0)
  2220.     {    stci_d(&mainstring[6], level);
  2221.         strcat((char*) mainstring, " of ");
  2222.         stci_d(tempstring, levels);
  2223.         strcat((char*) mainstring, (char*) tempstring);
  2224.         say(mainstring, colour);
  2225.     } else
  2226.     {    if (a == FIELDEDIT)
  2227.             say("Bonus Level", colour);
  2228.         else
  2229.         {    if (leveltype == TREASURE)
  2230.                             say("Bonus Level: Treasury!", colour);
  2231.                         elif (leveltype == DRIP)
  2232.                             say("Bonus Level: Drips!", colour);
  2233.                         else
  2234.                         {   // assert(leveltype == PENGUIN);
  2235.                             say("Bonus Level: Penguins!", colour);
  2236. }       }       }       }
  2237.  
  2238. MODULE SBYTE slowdown(SBYTE speed, ABOOL nitro)
  2239. {   speed *= 2;
  2240.     if (nitro)
  2241.     {   if (speed > VERYSLOW)
  2242.             speed = VERYSLOW;
  2243.     } elif (speed > SLOW)
  2244.         speed = SLOW;
  2245.     return(speed);
  2246. }
  2247.  
  2248. MODULE void slowloop(void)
  2249. {   SBYTE i, player, which, x, xx, y, yy;
  2250.     UBYTE c;
  2251.     ABOOL ok;
  2252.  
  2253.     if (ice)
  2254.     {   ice--;
  2255.     }
  2256.  
  2257.     /* decrement worm strength */
  2258.  
  2259.     for (player = 0; player <= 3; player++)
  2260.     {   if (worm[player].lives)
  2261.         {   if (worm[player].bias > 0)
  2262.             {   worm[player].bias--;
  2263.                 stat(player, BIAS);
  2264.             }
  2265.             if (worm[player].cutter > 0)
  2266.             {   worm[player].cutter--;
  2267.                 icon(player, CUTTER);
  2268.             }                
  2269.             if (worm[player].freedom > 0)
  2270.             {   worm[player].freedom--;
  2271.                 icon(player, FREEDOM);
  2272.             }
  2273.             if (worm[player].armour > 0)
  2274.             {   worm[player].armour--;
  2275.                 stat(player, ARMOUR);
  2276.     }   }   }
  2277.  
  2278.     /* blank out old causes */
  2279.  
  2280.     for (player = 0; player <= 3; player++)
  2281.     {   if (worm[player].lives > 0 && r > worm[player].causewait)
  2282.         {   drawcause(player, BLACK);
  2283.             worm[player].causewait = (ULONG) -1; /* most future time possible */
  2284.     }   }
  2285.  
  2286. if (!ice)
  2287. {   if (level)
  2288.     {   /* create goats */
  2289.         if
  2290.         (   (!arand(FREQ_GOAT))
  2291.         &&  findempty(&x, &y, TRUE)
  2292.         )
  2293.         {   for (i = 0; i <= CREATURES; i++)
  2294.             {   if (!creature[i].alive)
  2295.                 {   createcreature(GOAT, i, x, y, 0, 0, 255);
  2296.                     break;
  2297.         }   }   }
  2298.         /* create octopi */
  2299.         if
  2300.         (   (!arand(FREQ_OCTOPUS))
  2301.         &&  findempty(&x, &y, TRUE)
  2302.         )
  2303.         {   for (i = 0; i <= CREATURES; i++)
  2304.             {   if (!creature[i].alive)
  2305.                 {   createcreature(OCTOPUS, i, x, y, 0, 0, 255);
  2306.                     break;
  2307.         }   }   }
  2308.         /* create fish */
  2309.         if
  2310.         (   (!arand(FREQ_FISH))
  2311.         &&  findempty(&x, &y, TRUE)
  2312.         )
  2313.         {   for (i = 0; i <= CREATURES; i++)
  2314.             {   if (!creature[i].alive)
  2315.                 {   createcreature(FISH, i, x, y, 0, 0, 255);
  2316.                     break;
  2317.         }   }   }
  2318.         /* create orbs */
  2319.         if (!arand(FREQ_ORB) && findempty(&x, &y, FALSE))
  2320.         {   for (i = 0; i <= CREATURES; i++)
  2321.             {   if (!creature[i].alive)
  2322.                 {   createcreature(ORB, i, x, y, (arand(1) * 2) - 1, (arand(1) * 2) - 1, 255);
  2323.                     break;
  2324.         }   }   }
  2325.         /* create dogs */
  2326.         if (!arand(FREQ_DOG) && findempty(&x, &y, FALSE))
  2327.         {   for (i = 0; i <= CREATURES; i++)
  2328.             {   if (!(creature[i].alive))
  2329.                 {   createcreature(DOG, i, x, y, 0, 0, 255);
  2330.                     break;
  2331.         }   }   }
  2332.         /* create slime */
  2333.         if (!arand(FREQ_SLIME) && findempty(&x, &y, FALSE))
  2334.             change(x, y, SLIME);
  2335.         /* grow slime */
  2336.         if (!arand(FREQ_SLIMEGROW))
  2337.         {   for (x = 0; x <= FIELDX; x++)
  2338.                 for (y = 0; y <= FIELDY; y++)
  2339.                     if (field[x][y] == SLIME)
  2340.                         for (xx = x - 1; xx <= x + 1; xx++)
  2341.                             for (yy = y - 1; yy <= y + 1; yy++)
  2342.                                 if (valid(xx, yy) && field[xx][yy] == EMPTY && !arand(1))
  2343.                                     field[xx][yy] = TEMPSLIME;
  2344.             for (x = 0; x <= FIELDX; x++)
  2345.                 for (y = 0; y <= FIELDY; y++)
  2346.                     if (field[x][y] == TEMPSLIME)
  2347.                         change(x, y, SLIME);
  2348.         }
  2349.         /* create timebombs */
  2350.         if (!arand(FREQ_TIMEBOMB) && findempty(&x, &y, FALSE))
  2351.         {   for (i = 0; i <= CREATURES; i++)
  2352.             {   if (!(creature[i].alive))
  2353.                 {   createcreature(TIMEBOMB, i, x, y, 0, 0, 255);
  2354.                     break;
  2355.     }   }   }   }
  2356.  
  2357.     /* create drips */
  2358.     if
  2359.     (   ( level && !arand(FREQ_DRIP))
  2360.      || (!level && leveltype == DRIP && !arand(FREQ_DRIP / BONUSSPEEDUP))
  2361.     )
  2362.     {   x = arand(FIELDX);
  2363.         y = arand(2);
  2364.         c = field[x][y];
  2365.         if (c >= FIRSTEMPTY && c <= LASTEMPTY)
  2366.         {   for (i = 0; i <= CREATURES; i++)
  2367.             {   if (!creature[i].alive)
  2368.                 {   createcreature(DRIP, i, x, y, 0, 1, arand(3));
  2369.                     break;
  2370.     }   }   }   }
  2371.     // create penguins
  2372.     if
  2373.     (   (   ( level && !arand(FREQ_PENGUIN))
  2374.          || (!level && leveltype == PENGUIN && !arand(FREQ_PENGUIN / BONUSSPEEDUP))
  2375.         )
  2376.      && findempty(&x, &y, FALSE)
  2377.     )
  2378.     {   for (i = 0; i <= CREATURES; i++)
  2379.         {   if (!(creature[i].alive))
  2380.             {   createcreature(PENGUIN, i, x, y, 0, 0, 255);
  2381.                 break;
  2382.     }   }   }
  2383.     // create birds
  2384.     if
  2385.     (  (level && !arand(FREQ_BIRD) && findempty(&x, &y, FALSE))
  2386.     )
  2387.     {   // check whether this location is far enough away from the worms
  2388.         ok = TRUE;
  2389.         for (i = 0; i <= 3; i++)
  2390.         {   if
  2391.             (   worm[i].lives
  2392.              && abs(worm[i].x - x) < DISTANCE_BIRD * 2
  2393.              && abs(worm[i].y - y) < DISTANCE_BIRD * 2
  2394.             )
  2395.             {   ok = FALSE;
  2396.                 break;
  2397.         }   }
  2398.         if (ok)
  2399.         {   for (i = 0; i <= CREATURES; i++)
  2400.             {   if (!(creature[i].alive))
  2401.                 {   createcreature(BIRD, i, x, y, 0, 0, 255);
  2402.                     break;
  2403.     }   }   }   }
  2404.     /* create clouds */
  2405.     if
  2406.     (   (   ( level && !arand(FREQ_CLOUD))
  2407.          || (!level && leveltype == CLOUD && !arand(FREQ_CLOUD / BONUSSPEEDUP))
  2408.         )
  2409.      && findempty(&x, &y, FALSE)
  2410.     )
  2411.     {   for (i = 0; i <= CREATURES; i++)
  2412.         {   if (!creature[i].alive)
  2413.             {   if (x < FIELDX / 2)
  2414.                 {   createcreature(CLOUD, i, x, y, -1, 0, 255);
  2415.                 } else
  2416.                 {   createcreature(CLOUD, i, x, y,  1, 0, 255);
  2417.                 }
  2418.                 break;
  2419.     }   }   }
  2420.  
  2421.     /* create objects */
  2422.     for (which = 0; which <= LASTOBJECT; which++)
  2423.         if (level || leveltype != TREASURE || which == TREASURE)
  2424.         {   if (!arand(object[which].freq) && findempty(&x, &y, FALSE))
  2425.                 change(x, y, which);
  2426.         } elif (!arand(object[which].freq / 10) && findempty(&x, &y, FALSE))
  2427.             change(x, y, which);
  2428.  
  2429.     /* create teleports */
  2430.     if (!arand(FREQ_TELEPORT)
  2431.     && !teleport[level][2].alive
  2432.     && findempty(&(teleport[level][2].x), &(teleport[level][2].y), FALSE)
  2433.     && findempty(&(teleport[level][3].x), &(teleport[level][3].y), FALSE)
  2434.     && (teleport[level][2].x != teleport[level][3].x || teleport[level][2].y != teleport[level][3].y))
  2435.     {   teleport[level][2].alive = TRUE;
  2436.         teleport[level][3].alive = TRUE;
  2437.         change(teleport[level][2].x, teleport[level][2].y, TELEPORT);
  2438.         change(teleport[level][3].x, teleport[level][3].y, TELEPORT);
  2439. }   }
  2440. }
  2441.  
  2442. MODULE SBYTE speedup(SBYTE speed, ABOOL nitro)
  2443. {   speed /= 2;
  2444.     if (speed < FAST)
  2445.         speed = FAST;
  2446.     return(speed);
  2447. }
  2448.  
  2449. MODULE void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter)
  2450. {   SBYTE which;
  2451.     UBYTE filler;
  2452.  
  2453.     if (type == HEAD)
  2454.         filler = SILVER;
  2455.     else filler = EMPTY;
  2456.  
  2457.     if (c <= LASTOBJECT)
  2458.     {   if (!cutter)
  2459.         {   change(x, y, filler);
  2460.     }   }
  2461.     elif ((c >= FIRSTTAIL && c <= LASTTAIL) || c == WOOD || c == SLIME)
  2462.     {   change(x, y, filler);
  2463.     } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  2464.     {   if (!cutter && (type != HEAD || player != c - FIRSTHEAD))
  2465.         {   if (worm[c - FIRSTHEAD].armour == 0)
  2466.             {   worm[c - FIRSTHEAD].cause = BOMB;
  2467.                 worm[c - FIRSTHEAD].alive = FALSE;
  2468.                 if (type == HEAD)
  2469.                 {   worm[c - FIRSTHEAD].victor = player;
  2470.                 } else
  2471.                 {   worm[c - FIRSTHEAD].victor = -1;
  2472.             }   }
  2473.             else
  2474.             {   effect(FXUSE_ARMOUR);
  2475.     }   }   }
  2476.     elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  2477.     {   which = whichcreature(x, y, MISSILE, 255);
  2478.         if (!cutter)
  2479.         {   if (type == HEAD)
  2480.             {   if (player != c - FIRSTMISSILE)
  2481.                 {   wormkillcreature(player, which);
  2482.                     change(x, y, filler);
  2483.         }   }   }
  2484.         else
  2485.         {   creature[which].alive = FALSE;
  2486.             change(x, y, filler);
  2487.     }    }
  2488.     elif (c >= FIRSTDRIP && c <= LASTDRIP)
  2489.     {   if (!cutter)
  2490.         {   which = whichcreature(x, y, DRIP, 255);
  2491.             if (type == HEAD)
  2492.             {   wormkillcreature(player, which);
  2493.             } else
  2494.             {   creature[which].alive = FALSE;
  2495.             }
  2496.             change(x, y, filler);
  2497.     }   }
  2498.     elif
  2499.     (   c == CLOUD
  2500.      || c == DOG
  2501.      || c == FISH
  2502.      || c == FRAGMENT
  2503.      || c == GOAT
  2504.      || c == OCTOPUS
  2505.      || c == ORB
  2506.      || c == PENGUIN
  2507.      || c == WHIRLWIND
  2508.     )
  2509.     {   if (!cutter)
  2510.         {   which = whichcreature(x, y, c, 255);
  2511.             if (type == HEAD)
  2512.             {   wormkillcreature(player, which);
  2513.             } else
  2514.             {   creature[which].alive = FALSE;
  2515.             }
  2516.             change(x, y, filler);
  2517. }   }   }
  2518.  
  2519. void timeloop(void)
  2520. {   AUTO    TEXT  timedisplay[5] = {"#:##"};
  2521.     AUTO    UBYTE i;
  2522.     AUTO    SBYTE y;
  2523.     PERSIST ABOOL expired        = FALSE;
  2524.  
  2525.     secondsleft = atleast(secondsleft, 0);
  2526.     timedisplay[0] = 48 +  (secondsleft / 60);
  2527.     timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  2528.     timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  2529.  
  2530.     if (!level)
  2531.     {   say(timedisplay, worm[treasurer].colour);
  2532.         if (!secondsleft)
  2533.         {   level = reallevel + 1;
  2534.             secondsleft = SECONDSPERLEVEL;
  2535.             newlevel(treasurer);
  2536.     }   }
  2537.     elif (!secondsleft)
  2538.     {   if (!expired)
  2539.         {   effect(FXSIREN);
  2540.             say("Time expired!", WHITE);
  2541.             expired = TRUE;
  2542.  
  2543.             // create otters
  2544.             for (i = 0; i <= CREATURES; i++)
  2545.             {   if (!creature[i].alive)
  2546.                 {   for (y = 0; y <= FIELDY - 1; y++)
  2547.                     {   if (field[0][y] >= FIRSTEMPTY && field[0][y] <= LASTEMPTY)
  2548.                         {   createcreature(OTTER, i, 0,      y, 0,  1, 255);
  2549.                             break;
  2550.                     }   }
  2551.                     break;
  2552.             }   }
  2553.             for (i = 0; i <= CREATURES; i++)
  2554.             {   if (!creature[i].alive)
  2555.                 {   for (y = FIELDY - 1; y >= 0; y--)
  2556.                     {   if (field[FIELDX][y] >= FIRSTEMPTY && field[FIELDX][y] <= LASTEMPTY)
  2557.                         {   createcreature(OTTER, i, FIELDX, y, 0, -1, 255);
  2558.                             break;
  2559.                     }   }
  2560.                     break;
  2561.     }   }   }   }
  2562.     else
  2563.     {   expired = FALSE;
  2564.         say(timedisplay, WHITE);
  2565. }   }
  2566.  
  2567. void train(SCANCODE scancode)
  2568. {   SBYTE i, x, y;
  2569.  
  2570.     switch(scancode)
  2571.     {
  2572.     case HELP:
  2573.         trainer = !trainer;
  2574.     break;
  2575.     case NUMERICSLASH:
  2576.         /* Complete the level. */
  2577.         if (trainer)
  2578.         {   trainer = FALSE;
  2579.             for (i = 0; i <= LETTERS; i++)
  2580.             {   letters[i] = TRUE;
  2581.                 drawletter(FIRSTLETTER + i, NORMAL);
  2582.         }   }
  2583.     break;
  2584.     case NUMERICASTERISK:
  2585.         /* field[][] dump, for debugging purposes. */
  2586.         if (trainer)
  2587.         {   trainer = FALSE;
  2588.             say("Field dump...", PURPLE);
  2589.             for (x = 0; x <= FIELDX; x++)
  2590.                 for (y = 0; y <= FIELDY; y++)
  2591.                     draw(x, y, field[x][y]);
  2592.             anykey(FALSE);
  2593.         }
  2594.         break;
  2595.     case NUMERICPLUS:
  2596.         if (trainer)
  2597.         {   trainer = FALSE;
  2598.             say("Trainer activated!", PURPLE);
  2599.             anykey(FALSE);
  2600.             if (worm[1].lives > 0)
  2601.             {   worm[1].lives = LIVESLIMIT;
  2602.                 stat(1, LIFE);
  2603.                 worm[1].armour = MODELIMIT;
  2604.                 stat(1, ARMOUR);
  2605.                 worm[1].bias = BIASLIMIT;
  2606.                 stat(1, BIAS);
  2607.                 worm[1].ammo = AMMOLIMIT;
  2608.                 stat(1, AMMO);
  2609.                 worm[1].power = POWERLIMIT;
  2610.                 stat(1, POWER);
  2611.                 worm[1].nitro = TRUE;
  2612.                 stat(1, NITRO);
  2613.                 worm[1].affixer = TRUE;
  2614.                 icon(1, AFFIXER);
  2615.                 worm[1].remnants = TRUE;
  2616.                 icon(1, REMNANTS);
  2617.                 worm[1].sideshot = TRUE;
  2618.                 icon(1, SIDESHOT);
  2619.                 worm[1].pusher = TRUE;
  2620.                 icon(1, PUSHER);
  2621.                 worm[1].cutter = 100;
  2622.                 icon(1, CUTTER);
  2623.                 worm[1].encloser = TRUE;
  2624.                 icon(1, ENCLOSER);
  2625.                 trainer = FALSE;
  2626.         }   }
  2627.     break;
  2628.     default:
  2629.     break;
  2630. }   }
  2631.  
  2632. MODULE void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  2633. {
  2634. if (worm[player].nitro || !deltax || !deltay)
  2635. {    if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  2636.     {    worm[player].speed = speedup(worm[player].speed, worm[player].nitro);
  2637.         stat(player, NITRO);
  2638.     } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  2639.         {       worm[player].speed = slowdown(worm[player].speed, worm[player].nitro);
  2640.         stat(player, NITRO);
  2641.     } else
  2642.     {    worm[player].deltax = deltax;
  2643.         worm[player].deltay = deltay;
  2644. }    }
  2645. }
  2646.  
  2647. SBYTE valid(SBYTE x, SBYTE y)
  2648. {   if (x >= 0 && x <= FIELDX && y >= 0 && y <= FIELDY)
  2649.         return(TRUE);
  2650.     else return(FALSE);
  2651. }
  2652.  
  2653. MODULE UBYTE whichcreature(SBYTE x, SBYTE y, UBYTE species, UBYTE exception)
  2654. {   UBYTE i;    
  2655.  
  2656.     for (i = 0; i <= CREATURES; i++)
  2657.         if
  2658.         (   creature[i].alive
  2659.          && creature[i].x == x
  2660.          && creature[i].y == y
  2661.          && creature[i].species == species
  2662.          && i != exception
  2663.         )
  2664.             return i;
  2665.     return 255; /* error code */
  2666. }
  2667. MODULE SBYTE whichteleport(SBYTE x, SBYTE y)
  2668. {   SBYTE which;
  2669.  
  2670.     for (which = 0; which <= 3; which++)
  2671.         if (teleport[level][which].alive && teleport[level][which].x == x && teleport[level][which].y == y)
  2672.             return((SBYTE) which);
  2673.     return((SBYTE) -1); /* error code */
  2674. }
  2675.  
  2676. MODULE void wormbullet(SBYTE player)
  2677. {   ABOOL finished,
  2678.           flag     = FALSE,
  2679.           ok       = FALSE,
  2680.           lettered = FALSE;
  2681.     SBYTE distance,
  2682.           i, j,
  2683.           x, y;
  2684.     UBYTE c;
  2685.  
  2686.     if (!worm[player].ammo)
  2687.     {   stat(player, BONUS);
  2688.     if (worm[player].speed == FAST)
  2689.             distance = DISTANCE_FAST;
  2690.     elif (worm[player].speed == NORMAL)
  2691.            distance = DISTANCE_NORMAL;
  2692.         elif (worm[player].speed == SLOW)
  2693.            distance = DISTANCE_SLOW;
  2694.         else
  2695.         {  // assert(worm[player].speed == VERYSLOW);
  2696.            distance = DISTANCE_VERYSLOW;
  2697.         }
  2698.  
  2699.     /* check for metal */
  2700.  
  2701.     for (i = 1; i < distance; i++)
  2702.     {   x = xwrap(worm[player].x + (i * worm[player].deltax));
  2703.         y = ywrap(worm[player].y + (i * worm[player].deltay));
  2704.         if (field[x][y] == METAL)
  2705.         flag = TRUE;
  2706.     }
  2707.  
  2708.     if (!flag)
  2709.         {   // assert(abs(worm[player].deltax) <= 1 && abs(worm[player].deltay) <= 1);
  2710.         x = xwrap(worm[player].x + (worm[player].deltax * distance));
  2711.         y = ywrap(worm[player].y + (worm[player].deltay * distance));
  2712.             c = field[x][y];
  2713.             if (c == TELEPORT)
  2714.         {   i = whichteleport(x, y);
  2715.             if (!blocked(i, worm[player].deltax, worm[player].deltay))
  2716.             ok = TRUE;
  2717.         }
  2718.             if (ok || ((c < STONE || c > GOAT) && c != METAL))
  2719.             {   effect(FXDO_JUMP);
  2720.             worm[player].deltax *= distance;
  2721.             worm[player].deltay *= distance;
  2722.     }   }   }
  2723.     else
  2724.     {   effect(FXUSE_AMMO);
  2725.         worm[player].ammo--;
  2726.         stat(player, AMMO);
  2727.         if (worm[player].sideshot)
  2728.         {   bullet[7].alive      = bullet[8].alive      = TRUE;
  2729.             bullet[7].teleported = bullet[8].teleported = 0;
  2730.             bullet[7].visible    = bullet[8].visible    = TRUE;
  2731.             bullet[7].reflected  = bullet[8].reflected  = FALSE;
  2732.             bullet[7].x          = bullet[8].x          = worm[player].x;
  2733.             bullet[7].y          = bullet[8].y          = worm[player].y;
  2734.             if (!worm[player].deltax && worm[player].deltay)
  2735.             {   bullet[7].deltax = -1;
  2736.                 bullet[8].deltax = 1;
  2737.                 bullet[7].deltay = bullet[8].deltay = 0;
  2738.             } elif (worm[player].deltax && !worm[player].deltay)
  2739.             {   bullet[7].deltax = bullet[8].deltax = 0;
  2740.                 bullet[7].deltay = -1;
  2741.                 bullet[8].deltay = 1;
  2742.             } else /* worm is diagonal */
  2743.             {   if (worm[player].deltax == worm[player].deltay)
  2744.                 {   bullet[7].deltax = 1;
  2745.                     bullet[7].deltay = -1;
  2746.                 } else
  2747.                 {   bullet[7].deltax = -1;
  2748.                     bullet[7].deltay = -1;
  2749.                 }
  2750.                 bullet[8].deltax = -bullet[7].deltax;
  2751.                 bullet[8].deltay = -bullet[7].deltay;
  2752.         }   }
  2753.  
  2754.         for (i = 0; i <= worm[player].power; i++)
  2755.         {   bullet[i].alive      = TRUE;
  2756.             bullet[i].teleported = 0;
  2757.             bullet[i].visible    = TRUE;
  2758.             bullet[i].reflected  = FALSE;
  2759.             bullet[i].deltax     = worm[player].deltax;
  2760.             bullet[i].deltay     = worm[player].deltay;
  2761.             if (i % 2 == 0)
  2762.                 distance = i / 2;
  2763.             else distance = -((i + 1) / 2);
  2764.             if (worm[player].deltax == 0)
  2765.             {   bullet[i].x = worm[player].x + distance;
  2766.                 bullet[i].y = worm[player].y;
  2767.             } elif (worm[player].deltay == 0)
  2768.             {   bullet[i].x = worm[player].x;
  2769.                 bullet[i].y = worm[player].y + distance;
  2770.             } else
  2771.             {   switch (i)
  2772.                 {
  2773.                 case 0:
  2774.                     bullet[i].x = worm[player].x + worm[player].deltax;
  2775.                     bullet[i].y = worm[player].y + worm[player].deltay;
  2776.                 break;
  2777.                 case 1:
  2778.                     bullet[i].x = worm[player].x + worm[player].deltax;
  2779.                     bullet[i].y = worm[player].y;
  2780.                 break;
  2781.                 case 2:
  2782.                     bullet[i].x = worm[player].x;
  2783.                     bullet[i].y = worm[player].y + worm[player].deltay;
  2784.                 break;
  2785.                 case 3:
  2786.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2787.                     bullet[i].y = worm[player].y;
  2788.                 break;
  2789.                 case 4:
  2790.                     bullet[i].x = worm[player].x;
  2791.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2792.                 break;
  2793.                 case 5:
  2794.                     bullet[i].x = worm[player].x + worm[player].deltax * 2;
  2795.                     bullet[i].y = worm[player].y - worm[player].deltay;
  2796.                 break;
  2797.                 case 6:
  2798.                     bullet[i].x = worm[player].x - worm[player].deltax;
  2799.                     bullet[i].y = worm[player].y + worm[player].deltay * 2;
  2800.                 break;
  2801.                 default:
  2802.                 break;
  2803.         }   }   }
  2804.  
  2805.         /* Bullets are now set up. */
  2806.  
  2807.         finished = FALSE;
  2808.         while (!finished)
  2809.         {   finished = TRUE;
  2810.             for (i = 0; i <= 8; i++)
  2811.             {   if (bullet[i].alive)
  2812.                 {   finished = FALSE;
  2813.                     bullet[i].visible = TRUE;
  2814.                     if (bullet[i].reflected)
  2815.                     {   bullet[i].x -= bullet[i].deltax;
  2816.                         bullet[i].y -= bullet[i].deltay;
  2817.                     } else
  2818.                     {   bullet[i].x += bullet[i].deltax;
  2819.                         bullet[i].y += bullet[i].deltay;
  2820.                     }
  2821.                     x = bullet[i].x;
  2822.                     y = bullet[i].y;
  2823.                     c = field[x][y];
  2824.                     if (!(valid(x, y)))
  2825.                         bullet[i].alive = FALSE;
  2826.                     elif (x == worm[player].x && y == worm[player].y)
  2827.                     {   /* hit by own bullet */
  2828.                         bullet[i].alive = FALSE;
  2829.                         if (worm[player].armour == 0)
  2830.                         {   worm[player].cause = FIRSTFIRE + player;
  2831.                             worm[player].victor = -1;
  2832.                             worm[player].alive = FALSE;
  2833.                     }   }
  2834.                     elif (c >= FIRSTHEAD && c <= LASTHEAD)
  2835.                     {   if (worm[c - FIRSTHEAD].armour == 0)
  2836.                         {   worm[c - FIRSTHEAD].cause = FIRSTFIRE + player;
  2837.                             worm[c - FIRSTHEAD].victor = player;
  2838.                             worm[c - FIRSTHEAD].alive = FALSE;
  2839.                         } else effect(FXUSE_ARMOUR);
  2840.                         bullet[i].alive = FALSE;
  2841.                     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  2842.                     {   if (player != c - FIRSTPROTECTOR)
  2843.                         {   effect(FXUSE_PROTECTOR);
  2844.                             bullet[i].alive = FALSE;
  2845.                         } else bullet[i].visible = FALSE;
  2846.                     } elif (c >= FIRSTLETTER && c <= LASTLETTER)
  2847.                     {   wormletter(player, c);
  2848.                         lettered = TRUE;
  2849.                     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  2850.                     {   if (player != c - FIRSTMISSILE)
  2851.                             creature[whichcreature(x, y, MISSILE, 255)].alive = FALSE;
  2852.                         else bullet[i].visible = FALSE;
  2853.                     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  2854.                     {   j = whichcreature(x, y, DRIP, 255);
  2855.                         creature[j].alive = FALSE;
  2856.                     } else
  2857.                     {   switch(c)
  2858.                         {
  2859.                         case SLIME:
  2860.                         case WOOD:
  2861.                             // destroys one layer of it
  2862.                             bullet[i].alive = FALSE;
  2863.                             change(x, y, EMPTY);
  2864.                         break;
  2865.                         case METAL:
  2866.                             if (bullet[i].reflected)
  2867.                                 bullet[i].alive = FALSE;
  2868.                             else
  2869.                             {   bullet[i].reflected = TRUE;
  2870.                                 bullet[i].x -= bullet[i].deltax * 2;
  2871.                                 bullet[i].y -= bullet[i].deltay * 2;
  2872.                             }
  2873.                             break;
  2874.                         case STONE:
  2875.                             bullet[i].alive = FALSE;
  2876.                         break;
  2877.                         case TELEPORT:
  2878.                             j = whichteleport(bullet[i].x, bullet[i].y);
  2879.                             if (bullet[i].teleported == 2)
  2880.                                 bullet[i].alive = FALSE;
  2881.                             else
  2882.                             {   effect(FXUSE_TELEPORT);
  2883.                                 bullet[i].visible = FALSE;
  2884.                                 bullet[i].teleported++;
  2885.                                 bullet[i].x = teleport[level][partner(j)].x;
  2886.                                 bullet[i].y = teleport[level][partner(j)].y;
  2887.                             }
  2888.                         break;
  2889.                         case SKULL:
  2890.                             bullet[i].alive = FALSE;
  2891.                         break;
  2892.                         case CLOUD:
  2893.                         case DOG:
  2894.                         case FISH:
  2895.                         case FRAGMENT:
  2896.                         case GOAT:
  2897.                         case OCTOPUS:
  2898.                         case ORB:
  2899.                         case PENGUIN:
  2900.                         case WHIRLWIND:
  2901.                             bullet[i].alive = FALSE;
  2902.                             j = whichcreature(x, y, c, 255);
  2903.                             wormkillcreature(player, j);
  2904.                             change(x, y, EMPTY);
  2905.                         break;
  2906.                         case TIMEBOMB:
  2907.                             bullet[i].alive = FALSE;
  2908.                             creature[whichcreature(x, y, TIMEBOMB, 255)].alive = FALSE;
  2909.                             bombblast(BOMB, 0, x, y);
  2910.                             change(x, y, EMPTY);
  2911.                         break;
  2912.                         default:
  2913.                         break;
  2914.                     }   }
  2915.  
  2916.                     // x and y need this refreshing here
  2917.                     x = bullet[i].x;
  2918.                     y = bullet[i].y;
  2919.                     if (bullet[i].alive && bullet[i].visible)
  2920.                     {   draw(x, y, FIRSTFIRE + player);
  2921.                         if (worm[player].remnants)
  2922.                             field[x][y] = FIRSTFIRE + player;
  2923.                         elif (bullet[i].teleported)
  2924.                             change(x, y, GOLD);
  2925.                         else change(x, y, EMPTY);
  2926.         }   }   }   }
  2927.         if (lettered)
  2928.             putletter();
  2929.         clearkybd();
  2930. }   }
  2931.  
  2932. MODULE void wormletter(SBYTE player, UBYTE c)
  2933. {   switch(c)
  2934.     {
  2935.     case GREEN_C:
  2936.         effect(FX_C);
  2937.     break;
  2938.     case RED_O:
  2939.         effect(FX_O);
  2940.     break;
  2941.     case BLUE_M:
  2942.         effect(FX_M);
  2943.     break;
  2944.     case YELLOW_P:
  2945.        effect(FX_P);
  2946.     break;
  2947.     case GREEN_L:
  2948.         effect(FX_L);
  2949.     break;
  2950.     case BLUE_T:
  2951.         effect(FX_T);
  2952.     break;
  2953.     default:
  2954.         // assert(c == RED_E || c == YELLOW_E);
  2955.         effect(FX_E);
  2956.     break;
  2957.     }
  2958.     letters[c - FIRSTLETTER] = TRUE;
  2959.     drawletter(c, NORMAL);
  2960.     wormscore(player, POINTS_LETTER);
  2961. }
  2962.  
  2963. /* NAME     wormloop -- controls worms and protectors
  2964. SYNOPSIS    wormloop(SBYTE);
  2965. FUNCTION    Amiga-worm thinking, processing one keystroke from the
  2966.             worm's queue, all the worm's protectors' control, the
  2967.             worm's control.
  2968. MODULE      engine.c */
  2969.  
  2970. MODULE void wormloop(SBYTE player)
  2971. {   AUTO    SBYTE bestx = 0, besty = 0, // to avoid spurious warnings
  2972.                   dirx, diry, i, j, thisprot, x, y;
  2973.     AUTO    SWORD bestgood, good;
  2974.     AUTO    UBYTE c;
  2975.  
  2976.    /*  Amiga worm control
  2977.        Remove a keystroke from the worm queue
  2978.        Move worm (and add a keystroke to the dog queue)
  2979.        Check for enclosure
  2980.        Move protectors
  2981.        Collision detection
  2982.  
  2983.     AI: Amiga worm control.
  2984.  
  2985.     Worm checks ahead, left and right one square. Assigns opinions
  2986.     to those three choices and then takes the appropriate one.
  2987.  
  2988.     Things which slow the worm down are doubly feared; this is to avoid
  2989.     endless ramming situations. */
  2990.  
  2991.     if (worm[player].control == AMIGA)
  2992.     {   if (!arand(50))
  2993.             wormqueue(player, arand(2) - 1, arand(2) - 1);
  2994.         else
  2995.         {   bestgood = -128;
  2996.  
  2997.             for (i = 0; i <= 2; i++)
  2998.             {   switch(i)
  2999.                 {
  3000.                 case 0:
  3001.                     dirx = worm[player].deltax;
  3002.                     diry = worm[player].deltay;
  3003.                 break;
  3004.                 case 1:
  3005.                     if (worm[player].deltax == 0) /* if going north or south */
  3006.                     {   dirx = -1;                /* then look west */
  3007.                         diry = 0;
  3008.                     } else                        /* if going east or west */
  3009.                     {   dirx = 0;                 /* then look north */
  3010.                         diry = -1;
  3011.                     }
  3012.                 break;
  3013.                 case 2:
  3014.                     if (worm[player].deltax == 0) /* if going north or south */
  3015.                     {   dirx = 1;                 /* then look east */
  3016.                         diry = 0;
  3017.                     } else                        /* if going east or west */
  3018.                     {   dirx = 0;                 /* then look south */
  3019.                         diry = 1;
  3020.                     }
  3021.                 break;
  3022.                 default:
  3023.                     dirx = diry = 0; // to prevent spurious warnings
  3024.                 break;
  3025.                 }
  3026.                 c = field[xwrap(worm[player].x + dirx)][ywrap(worm[player].y + diry)];
  3027.                 if (c >= FIRSTLETTER && c <= LASTLETTER)
  3028.                     good = POINTS_LETTER;
  3029.                 elif (c >= FIRSTHEAD && c <= LASTHEAD)
  3030.                     good = -(PAIN_HEAD);
  3031.                 elif (c <= LASTOBJECT)
  3032.                     good = (SWORD) object[c].score;
  3033.                 elif (c == FIRSTPROTECTOR + player)
  3034.                     good = POINTS_EMPTY;
  3035.                 elif (c >= FIRSTFIRE && c <= LASTFIRE)
  3036.         {   if (player == c - FIRSTFIRE)
  3037.                 good = -1;
  3038.                     else good = -(PAIN_REMNANT);
  3039.                 } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3040.                 {   if (player == c - FIRSTMISSILE)
  3041.                         good = 0;
  3042.                     else good = -(PAIN_MISSILE);
  3043.                 } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3044.                 {   if (player == c - FIRSTDRIP)
  3045.                         good = SCORE_DRIP;
  3046.                     else good = -(PAIN_DRIP);
  3047.                 } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3048.                 {   if (worm[player].armour > 10)
  3049.                         if (player != c - FIRSTTAIL)
  3050.                             good = POINTS_TURNSILVER;
  3051.                         else good = 0;
  3052.                     elif (player == c - FIRSTTAIL)
  3053.                         good = -(PAIN_FRIENDLYTAIL);
  3054.                     else good = -(PAIN_ENEMYTAIL);
  3055.                 } else switch(c)
  3056.                 {
  3057.                 case SKULL:
  3058.                     good = POINTS_SKULL;
  3059.                 break;
  3060.                 case GOLD:
  3061.                     good = POINTS_GOLD;
  3062.                 break;
  3063.                 case SILVER:
  3064.                     good = POINTS_SILVER;
  3065.                 break;
  3066.                 case EMPTY:
  3067.                     good = POINTS_EMPTY;
  3068.                 break;
  3069.                 case SLIME:
  3070.                     if (worm[player].armour > 0)
  3071.                         good = 0;
  3072.                     else good = -(PAIN_SLIME);
  3073.                 break;
  3074.                 case WOOD:
  3075.                     if (worm[player].armour > 0)
  3076.                         good = 0;
  3077.                     else good = -(PAIN_WOOD);
  3078.                 break;
  3079.                 case STONE:
  3080.                     good = -(PAIN_STONE * 2);
  3081.                 break;
  3082.                 case METAL:
  3083.                     good = -(PAIN_METAL * 2);
  3084.                 break;
  3085.                 case GOAT:
  3086.                     good = -(PAIN_GOAT * 2);
  3087.                 break;
  3088.                 case CLOUD:
  3089.                     good = -(PAIN_CLOUD);
  3090.                 break;
  3091.                 case DOG:
  3092.                     good = -(PAIN_DOG);
  3093.                 break;
  3094.                 case FISH:
  3095.                     good = -(PAIN_FISH);
  3096.                 break;
  3097.                 case FRAGMENT:
  3098.                     good = -(PAIN_FRAGMENT);
  3099.                 break;
  3100.                 case OCTOPUS:
  3101.                     good = -(PAIN_OCTOPUS * 2);
  3102.                 break;
  3103.                 case ORB:
  3104.                     good = -(PAIN_ORB);
  3105.                 break;
  3106.                 case WHIRLWIND:
  3107.                     good = -(PAIN_WHIRLWIND);
  3108.                 break;
  3109.                 default:
  3110.                     good = 0;
  3111.                 break;
  3112.                 }
  3113.                 if (good > bestgood)
  3114.                 {   bestx = dirx;
  3115.                     besty = diry;
  3116.                     bestgood = good;
  3117.             }   }
  3118.             if (bestgood < -2 && !arand(1))
  3119.             {   // turn in any of the 8 directions, or fire
  3120.                 bestx = (arand(1) * 2) - 1;
  3121.                 besty = (arand(1) * 2) - 1;
  3122.             }
  3123.             elif (bestgood < -1 && !arand(1))
  3124.                 wormqueue(player, 0, 0);
  3125.             elif (bestgood < 0 && !arand(5))
  3126.                 wormqueue(player, 0, 0);
  3127.             elif (bestx != worm[player].deltax || besty != worm[player].deltay)
  3128.                 wormqueue(player, bestx, besty);
  3129.     }   }
  3130.  
  3131.     /* remove a keystroke from the worm queue */
  3132.  
  3133.     if (worm[player].pos != -1)                         
  3134.     {   if (first && worm[2].lives && worm[2].control == JOYSTICK)
  3135.         {   first = FALSE;
  3136.             /* Yes, this is defensive programming :-(
  3137.             Because the first time the blue worm has joystick control, a
  3138.             bizarre firebutton event seems to occur. */
  3139.         } else
  3140.         {   if (thewormqueue[player][0].deltax == 0 && thewormqueue[player][0].deltay == 0)
  3141.                 wormbullet(player);
  3142.             else turnworm(player, thewormqueue[player][0].deltax, thewormqueue[player][0].deltay);
  3143.         }
  3144.         if (--worm[player].pos != -1)
  3145.         {   for (i = 0; i <= worm[player].pos; i++)
  3146.             {   thewormqueue[player][i].deltax = thewormqueue[player][i + 1].deltax;
  3147.                 thewormqueue[player][i].deltay = thewormqueue[player][i + 1].deltay;
  3148.     }   }   }
  3149.  
  3150.     /* move worm */
  3151.  
  3152.     change(worm[player].x, worm[player].y, worm[player].last);
  3153.     worm[player].x = xwrap(worm[player].x + worm[player].deltax);
  3154.     worm[player].y = ywrap(worm[player].y + worm[player].deltay);
  3155.     if (worm[player].freedom)
  3156.         worm[player].last = FIRSTFIRE + player;
  3157.     else worm[player].last = FIRSTTAIL + player;
  3158.  
  3159.     for (i = 0; i <= CREATURES; i++)
  3160.     {   if (creature[i].alive && creature[i].species == DOG && creature[i].dormant > DORMANT && creature[i].type == player)
  3161.         {   if (!worm[player].rammed)
  3162.                 dogqueue(i, worm[player].deltax, worm[player].deltay);
  3163.             if (creature[i].dormant < CHASING)
  3164.             {   creature[i].dormant++;
  3165.                 draw(creature[i].x, creature[i].y, DOGAWAKENING);
  3166.     }   }   }
  3167.  
  3168.     /* The deltas are not changed back to the range of -1..1 until after
  3169.     the dogs have looked at the queue. This enables them to jump properly. */
  3170.  
  3171.     worm[player].rammed = FALSE;
  3172.     worm[player].deltax = bsign(worm[player].deltax);
  3173.     worm[player].deltay = bsign(worm[player].deltay);
  3174.  
  3175.     /*  check for enclosure
  3176.         #####
  3177.         #...#
  3178.         #...# . = interior
  3179.         #...# # = tail
  3180.         ####! ! = head */
  3181.  
  3182.     for (i = 2; i <= 7; i++) // for each size of interior
  3183.     {   for (j = 0; j <= 3; j++) // four times, once for each direction
  3184.         {   checkrectangle(j, player, i, i);
  3185.             if (worm[player].encloser)
  3186.             {   checkrectangle(j, player, i, i + 1);
  3187.                 checkrectangle(j, player, i + 1, i);
  3188.     }   }   }
  3189.  
  3190.     // move protectors
  3191.  
  3192.     for (i = 0; i <= PROTECTORS; i++)
  3193.     {   if (protector[player][i].alive)
  3194.         {   if (protector[player][i].visible)
  3195.             {   change(protector[player][i].x, protector[player][i].y, protector[player][i].last);
  3196.             } else protector[player][i].visible = TRUE;
  3197.             protector[player][i].last = EMPTY;
  3198.             if (i == NOSE)
  3199.             {   protector[player][i].relx = worm[player].deltax * DISTANCE_NOSE;
  3200.                 protector[player][i].rely = worm[player].deltay * DISTANCE_NOSE;
  3201.                 if (!worm[player].affixer)
  3202.                 {   if (worm[player].position == -1)
  3203.                         worm[player].posidir = 1;
  3204.                     elif (worm[player].position == 1)
  3205.                         worm[player].posidir = -1;
  3206.                     worm[player].position += worm[player].posidir;
  3207.                     if (worm[player].deltax == 0)
  3208.                         protector[player][i].relx = worm[player].position;
  3209.                     elif (worm[player].deltay == 0)
  3210.                         protector[player][i].rely = worm[player].position;
  3211.                     elif (worm[player].position == -1)
  3212.                         protector[player][i].relx = worm[player].deltax * (DISTANCE_NOSE - 1);
  3213.                     elif (worm[player].position == 1)
  3214.                         protector[player][i].rely = worm[player].deltay * (DISTANCE_NOSE - 1);
  3215.             }   }
  3216.             elif (!worm[player].affixer)
  3217.             {   if (protector[player][i].relx == 1 && protector[player][i].rely == -1)
  3218.                 {   protector[player][i].deltax = 0;
  3219.                     protector[player][i].deltay = 1;
  3220.                 } elif (protector[player][i].relx == 1 && protector[player][i].rely == 1)
  3221.                 {   protector[player][i].deltax = -1;
  3222.                     protector[player][i].deltay = 0;
  3223.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == 1)
  3224.                 {   protector[player][i].deltax = 0;
  3225.                     protector[player][i].deltay = -1;
  3226.                 } elif (protector[player][i].relx == -1 && protector[player][i].rely == -1)
  3227.                 {   protector[player][i].deltax = 1;
  3228.                     protector[player][i].deltay = 0;
  3229.                 }
  3230.                 protector[player][i].relx += protector[player][i].deltax;
  3231.                 protector[player][i].rely += protector[player][i].deltay;
  3232.             }
  3233.             protector[player][i].x = worm[player].x + protector[player][i].relx;
  3234.             protector[player][i].y = worm[player].y + protector[player][i].rely;
  3235.             if (!valid(protector[player][i].x, protector[player][i].y))
  3236.             {   protector[player][i].visible = FALSE;
  3237.     }   }   }
  3238.  
  3239.     // head collision detection
  3240.     wormcol(player, worm[player].x, worm[player].y);
  3241.     // draw head
  3242.     field[worm[player].x][worm[player].y] = FIRSTHEAD + player;
  3243.     drawhead(player, worm[player].x, worm[player].y);
  3244.  
  3245.     updatearrow(worm[player].arrowy);
  3246.     worm[player].arrowy = worm[player].y;
  3247.     updatearrow(worm[player].arrowy);
  3248.  
  3249.     // protector collision detection
  3250.     for (thisprot = 0; thisprot <= PROTECTORS; thisprot++)
  3251.     {   if (protector[player][thisprot].alive && protector[player][thisprot].visible)
  3252.         {   protcol(player, protector[player][thisprot].x, protector[player][thisprot].y, thisprot);
  3253.             // draw protector
  3254.             if (protector[player][thisprot].alive && protector[player][thisprot].visible) // in case protector has just been killed, etc.
  3255.             {   change(protector[player][thisprot].x, protector[player][thisprot].y, FIRSTPROTECTOR + player);
  3256.     }   }   }
  3257.  
  3258.     if (worm[player].cutter)
  3259.     {   // straight ahead
  3260.         x = xwrap(worm[player].x + worm[player].deltax);
  3261.         y = ywrap(worm[player].y + worm[player].deltay);
  3262.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3263.         // left
  3264.         if (!worm[player].deltax || !worm[player].deltay)
  3265.         {   // if orthagonal
  3266.             x = xwrap(worm[player].x + worm[player].deltay);
  3267.             y = ywrap(worm[player].y - worm[player].deltax);
  3268.         } else // diagonal
  3269.         {   if (worm[player].deltax == worm[player].deltay)
  3270.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3271.                 y = ywrap(worm[player].y - worm[player].deltay);
  3272.             } else
  3273.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3274.                 y = ywrap(worm[player].y + worm[player].deltay);
  3275.         }   }
  3276.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3277.         // right
  3278.         if (!worm[player].deltax || !worm[player].deltay)
  3279.         {   // if orthagonal
  3280.             x = xwrap(worm[player].x - worm[player].deltay);
  3281.             y = ywrap(worm[player].y + worm[player].deltax);
  3282.         } else // diagonal
  3283.         {   if (worm[player].deltax == worm[player].deltay)
  3284.             {   x = xwrap(worm[player].x - worm[player].deltax);
  3285.                 y = ywrap(worm[player].y + worm[player].deltay);
  3286.             } else
  3287.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3288.                 y = ywrap(worm[player].y - worm[player].deltay);
  3289.         }   }
  3290.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3291.         // ahead left
  3292.         if (!worm[player].deltax || !worm[player].deltay)
  3293.         {   // if orthagonal
  3294.             if (worm[player].deltax) // if east or west
  3295.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3296.                 y = ywrap(worm[player].y - worm[player].deltax);
  3297.             } else // north or south
  3298.             {   x = xwrap(worm[player].x + worm[player].deltay);
  3299.                 y = ywrap(worm[player].y + worm[player].deltay);
  3300.         }   }
  3301.         else // diagonal
  3302.         {   if (worm[player].deltax == worm[player].deltay)
  3303.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3304.                 y = worm[player].y;
  3305.             } else
  3306.             {   x = worm[player].x;
  3307.                 y = ywrap(worm[player].y + worm[player].deltay);
  3308.         }   }
  3309.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3310.         // ahead right
  3311.         if (!worm[player].deltax || !worm[player].deltay)
  3312.         {   // if orthagonal
  3313.             if (worm[player].deltax) // if east or west
  3314.             {   x = xwrap(worm[player].x + worm[player].deltax);;
  3315.                 y = ywrap(worm[player].y + worm[player].deltax);
  3316.             } else // north or south
  3317.             {   x = xwrap(worm[player].x - worm[player].deltay);
  3318.                 y = ywrap(worm[player].y + worm[player].deltay);
  3319.         }   }
  3320.         else // diagonal
  3321.         {   if (worm[player].deltax == worm[player].deltay)
  3322.             {   x = worm[player].x;
  3323.                 y = ywrap(worm[player].y + worm[player].deltay);
  3324.             } else
  3325.             {   x = xwrap(worm[player].x + worm[player].deltax);
  3326.                 y = worm[player].y;
  3327.         }   }
  3328.         squareblast(HEAD, player, field[x][y], x, y, TRUE);
  3329. }   }
  3330.  
  3331. MODULE void protcol(SBYTE player, SBYTE x, SBYTE y, SBYTE thisprot)
  3332. {   UBYTE c = field[x][y];
  3333.     SBYTE i;
  3334.  
  3335.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  3336.     {   protworm(x, y, player, c - FIRSTHEAD);
  3337.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  3338.     {   protprot(x, y, player, c - FIRSTPROTECTOR);
  3339.     } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  3340.     {   if (player == c - FIRSTTAIL)
  3341.         {   protector[player][thisprot].visible = FALSE;
  3342.     }   }
  3343.     elif
  3344.     (   c == STONE
  3345.      || c == WOOD
  3346.      || c == METAL
  3347.      || c == TIMEBOMB
  3348.      || c == TELEPORT
  3349.      || c == FIRSTFIRE + player
  3350.     )
  3351.     {   protector[player][thisprot].visible = FALSE;
  3352.     } elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  3353.     {   i = whichcreature(x, y, MISSILE, 255);
  3354.         protcreature(player, i);
  3355.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  3356.     {   i = whichcreature(x, y, DRIP, 255);
  3357.         protcreature(player, i);
  3358.     } elif
  3359.     (   c == BIRD
  3360.      || c == CLOUD
  3361.      || c == DOG
  3362.      || c == FRAGMENT
  3363.      || c == ORB
  3364.      || c == PENGUIN
  3365.      || c == WHIRLWIND
  3366.     )
  3367.     {   i = whichcreature(x, y, c, 255);
  3368.         protcreature(player, i);
  3369.     } else
  3370.     {   bothcol(player, x, y);
  3371. }   }
  3372.  
  3373. MODULE void bothcol(SBYTE player, SBYTE x, SBYTE y)
  3374. {   UBYTE c = field[x][y];
  3375.     SBYTE i, j;
  3376.  
  3377.     if (c >= FIRSTLETTER && c <= LASTLETTER)
  3378.     {   wormletter(player, c);
  3379.         putletter();
  3380.     } elif (c <= LASTOBJECT)
  3381.     {   wormscore(player, wormobject(player, x, y));
  3382.     } else
  3383.     {   switch(c)
  3384.         {
  3385.         case EMPTY:
  3386.             wormscore(player, POINTS_EMPTY);
  3387.         break;
  3388.         case SILVER:
  3389.             wormscore(player, POINTS_SILVER);
  3390.         break;
  3391.         case GOLD:
  3392.             wormscore(player, POINTS_GOLD);
  3393.         break;
  3394.         case DYNAMITE:
  3395.             effect(FXUSE_BOMB);
  3396.             banging = TRUE;
  3397.             bangdynamite(x, y, player);
  3398.             wormscore(player, worm[player].dynamitescore);
  3399.             worm[player].dynamitescore = 0;
  3400.         break;
  3401.         case SKULL:
  3402.             effect(FXGET_SKULL);
  3403.             wormscore(player, POINTS_SKULL);
  3404.             j = -1; // for safety
  3405.             for (i = 0; i <= 3; i++)
  3406.             {   if (!worm[i].lives && x == worm[i].x && y == worm[i].y && worm[i].control != NONE)
  3407.                     j = i;
  3408.             }
  3409.             if (j != -1)
  3410.             {   worm[player].bias += worm[j].bias;
  3411.                 if (worm[player].bias > 0)
  3412.                 {   if (worm[player].armour > BIASLIMIT)
  3413.                         worm[player].armour = BIASLIMIT;
  3414.                     stat(player, BIAS);
  3415.                     worm[j].bias = 0;
  3416.                     stat(j, BIAS);
  3417.                 }
  3418.                 worm[player].multi *= worm[j].multi;
  3419.                 if (worm[player].multi > 1)
  3420.                 {   if (worm[player].multi > MULTILIMIT)
  3421.                         worm[player].multi = MULTILIMIT;
  3422.                 }
  3423.                 worm[player].power += worm[j].power;
  3424.                 if (worm[player].power > 1)
  3425.                 {   if (worm[player].power > POWERLIMIT)
  3426.                         worm[player].power = POWERLIMIT;
  3427.                     stat(player, POWER);
  3428.                     worm[j].power = 0;
  3429.                     stat(j, POWER);
  3430.                 }
  3431.                 worm[player].ammo += worm[j].ammo;
  3432.                 if (worm[player].ammo > 0)
  3433.                 {   if (worm[player].ammo > AMMOLIMIT)
  3434.                         worm[player].ammo = AMMOLIMIT;
  3435.                     stat(player, AMMO);
  3436.                     worm[j].ammo = 0;
  3437.                     stat(j, AMMO);
  3438.                 }
  3439.                 worm[player].armour += worm[j].armour;
  3440.                 if (worm[player].armour > 0)
  3441.                 {   if (worm[player].armour > MODELIMIT)
  3442.                         worm[player].armour = MODELIMIT;
  3443.                     stat(player, ARMOUR);
  3444.                     worm[j].armour = 0;
  3445.                     stat(j, ARMOUR);
  3446.                 }
  3447.                 if (worm[j].nitro)
  3448.                 {   worm[player].nitro = TRUE;
  3449.                     stat(player, NITRO);
  3450.                     worm[j].nitro = FALSE;
  3451.                     worm[j].speed = NORMAL;
  3452.                     stat(j, NITRO);
  3453.                 }
  3454.                 if (worm[j].affixer)
  3455.                 {   worm[player].affixer = TRUE;
  3456.                     icon(player, AFFIXER);
  3457.                     worm[j].affixer = FALSE;
  3458.                     icon(j, AFFIXER);
  3459.                 }
  3460.                 if (worm[j].remnants)
  3461.                 {   worm[player].remnants = TRUE;
  3462.                     icon(player, REMNANTS);
  3463.                     worm[j].remnants = FALSE;
  3464.                     icon(j, REMNANTS);
  3465.                 }
  3466.                 if (worm[j].sideshot)
  3467.                 {   worm[player].sideshot = TRUE;
  3468.                     icon(player, SIDESHOT);
  3469.                     worm[j].sideshot = FALSE;
  3470.                     icon(j, SIDESHOT);
  3471.                 }
  3472.                 if (worm[j].pusher)
  3473.                 {   worm[player].pusher = TRUE;
  3474.                     icon(player, PUSHER);
  3475.                     worm[j].pusher = FALSE;
  3476.                     icon(j, PUSHER);
  3477.                 }
  3478.                 if (worm[j].encloser)
  3479.                 {   worm[player].encloser = TRUE;
  3480.                     icon(player, ENCLOSER);
  3481.                     worm[j].encloser = FALSE;
  3482.                     icon(j, ENCLOSER);
  3483.                 }
  3484.                 if (worm[j].cutter)
  3485.                 {   worm[player].cutter += worm[j].cutter;
  3486.                     icon(player, CUTTER);
  3487.                     worm[j].cutter = 0;
  3488.                     icon(j, CUTTER);
  3489.             }   }
  3490.             else ; // assert(0);
  3491.         break;
  3492.         default:
  3493.         break;
  3494. }   }   } 
  3495.  
  3496. AGLOBAL void wormscore(SBYTE player, ULONG score)
  3497. {   worm[player].score += score * worm[player].multi * players;
  3498.     stat(player, BONUS);
  3499. }
  3500.  
  3501. SBYTE xwrap(SBYTE x)
  3502. {    if (x < 0)
  3503.         x += FIELDX + 1;
  3504.     elif (x > FIELDX)
  3505.         x -= FIELDX + 1;
  3506.     return(x);
  3507. }
  3508. SBYTE ywrap(SBYTE y)
  3509. {    if (y < 0)
  3510.         y += FIELDY + 1;
  3511.     elif (y > FIELDY)
  3512.         y -= FIELDY + 1;
  3513.     return(y);
  3514. }
  3515.  
  3516. MODULE void ramming(SBYTE player)
  3517. {   SBYTE i;
  3518.  
  3519.     worm[player].rammed = TRUE;
  3520.     worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  3521.     worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  3522.     for (i = 0; i <= PROTECTORS; i++)
  3523.     {   /* no point checking whether the protectors are alive or dead */
  3524.         protector[player][i].x -= worm[player].deltax;
  3525.         protector[player][i].y -= worm[player].deltay;
  3526. }   }
  3527.  
  3528. MODULE SWORD atleast(SWORD value, SWORD minimum)
  3529. {   if (value < minimum)
  3530.         return(minimum);
  3531.     else return(value);
  3532. }
  3533.  
  3534. MODULE void __inline change(SBYTE x, SBYTE y, UBYTE image)
  3535. {   // assert(valid(x, y));
  3536.     field[x][y] = image;
  3537.     draw(x, y, image);
  3538. }
  3539.  
  3540. /* WormWars FSET format for fieldset contents and high score table (Amiga
  3541. and IBM-PC), as follows:
  3542.  
  3543. header
  3544.         TEXT[]                          "FSET x.x" (NULL-terminated)
  3545.     SBYTE                levels;
  3546. high score table
  3547.     for (slot = 0; slot <= HISCORES; slot++)
  3548.     {    SBYTE            hiscore[slot].player,
  3549.                     hiscore[slot].level;
  3550.         SLONG            hiscore[slot].score;
  3551.         TEXT[]            hiscore[slot].name (NULL-terminated)
  3552.         TEXT[]            hiscore[slot].time (NULL-terminated)
  3553.         TEXT[]            hiscore[slot].date (NULL-terminated)
  3554.     }
  3555. level data
  3556.     for (level = 0; level <= levels; level++)
  3557.     {    SBYTE            startx[level],
  3558.                                         starty[level];
  3559.         ABOOL            teleport[level][0].alive;
  3560.         SBYTE            teleport[level][0].x,
  3561.                                         teleport[level][0].y;
  3562.         ABOOL            teleport[level][1].alive;
  3563.         SBYTE            teleport[level][1].x,
  3564.                                         teleport[level][1].y;
  3565.         for (x = 0; x <= FIELDX; x++)
  3566.             for (y = 0; y <= FIELDY; y++)
  3567.                 SBYTE    board[level][x][y];
  3568.     }
  3569. version string
  3570.         TEXT[]                          "$VER: Worm Wars x.x (dd.mm.yy) $" (NULL-terminated) */
  3571.  
  3572. MODULE SBYTE onlyworm(ABOOL alive)
  3573. {   SBYTE i,
  3574.           theworm = -1, // to prevent spurious warnings
  3575.           worms   = 0;
  3576.  
  3577.     for (i = 0; i <= 3; i++)
  3578.         if (worm[i].control != NONE && ((!alive) || worm[i].lives))
  3579.         {   theworm = i;
  3580.             worms++;
  3581.         }
  3582.     if (worms == 1)
  3583.         return (SBYTE) theworm;
  3584.     else return -1;
  3585. }
  3586.  
  3587. MODULE void wormkillcreature(UBYTE player, UBYTE which)
  3588. {   /* This is defensive programming. Sometimes squareblast() finds an
  3589.        orb on the field for which there is no corresponding creature
  3590.        (ie. an 'orphan orb'. whichcreature() on such a square will
  3591.        return 255. */
  3592.  
  3593.     if (which != 255)
  3594.     {   wormscore(player, creature[which].score);
  3595.         creature[which].alive = FALSE;
  3596.         if (worm[player].bias)
  3597.         {   worm[player].lives++;
  3598.             stat(player, LIFE);
  3599.         }
  3600.         if (creature[which].species == ORB)
  3601.         {   effect(FXDEATH_ORB);
  3602.         } elif (creature[which].species == FRAGMENT)
  3603.         {   effect(FXDEATH_FRAGMENT);
  3604.         } elif (creature[which].species == DRIP)
  3605.         {   effect(FXGET_DRIP);
  3606.         } elif (creature[which].species == PENGUIN)
  3607.         {   effect(FXDEATH_PENGUIN);
  3608. }   }   }
  3609. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3610. {   if (worm[which1].armour == 0 && worm[which2].armour == 0)
  3611.     {   /* both worms die */
  3612.         worm[which1].cause  = FIRSTHEAD + which2;
  3613.         worm[which1].alive  = FALSE;
  3614.         worm[which1].victor = -1;
  3615.         worm[which2].cause  = FIRSTHEAD + which1;
  3616.         worm[which2].alive  = FALSE;
  3617.         worm[which2].victor = -1;
  3618.     } elif (worm[which1].armour > 0 && worm[which2].armour == 0)
  3619.     {   /* 1st worm lives, 2nd worm dies  */
  3620.         worm[which2].cause  = FIRSTHEAD + which1;
  3621.         worm[which2].alive  = FALSE;
  3622.         worm[which2].victor = which1;
  3623.     } elif (worm[which1].armour == 0 && worm[which2].armour > 0)
  3624.     {   /* 1st worm dies, 2nd worm lives */
  3625.         worm[which1].cause  = FIRSTHEAD + which2;
  3626.         worm[which1].alive  = FALSE;
  3627.         worm[which1].victor = which2;
  3628. }   }
  3629. MODULE void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3630. {   SBYTE i, j = -1; // to prevent spurious warnings
  3631.  
  3632.     for (i = 0; i <= PROTECTORS; i++)
  3633.          if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  3634.          {    j = i;
  3635.               break;
  3636.          }
  3637.  
  3638.     if (which1 != which2)
  3639.     {   if (worm[which2].armour == 0)
  3640.         {   effect(FXUSE_PROTECTOR);
  3641.             worm[which2].cause  = FIRSTPROTECTOR + which1;
  3642.             worm[which2].victor = which1;
  3643.             worm[which2].alive  = FALSE;
  3644.         } else
  3645.         {   effect(FXUSE_ARMOUR);
  3646.             protector[which1][j].visible = FALSE;
  3647.     }   }
  3648.     else
  3649.     {   /* protector is over worm's own head; caused by ramming */
  3650.         protector[which1][j].visible = FALSE;
  3651. }   }
  3652. MODULE void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  3653. {   SBYTE i, p1 = -1, p2 = -1; // to prevent spurious warnings
  3654.  
  3655.     /* Find both protectors */
  3656.  
  3657.     for (i = 0; i <= PROTECTORS; i++)
  3658.     {   if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  3659.             p1 = i;
  3660.         if (protector[which2][i].alive && protector[which2][i].x == x && protector[which2][i].y == y)
  3661.             p2 = i;
  3662.     }
  3663.     protector[which1][p1].alive = FALSE;
  3664.     protector[which2][p2].alive = FALSE;
  3665.     change(x, y, EMPTY);
  3666. }
  3667.  
  3668. MODULE ULONG wormobject(UBYTE player, SBYTE x, SBYTE y)
  3669. {   AUTO    UBYTE c = field[x][y], d;
  3670.     AUTO    ULONG score = object[c].score;
  3671.     AUTO    UBYTE i, j, generated = 0;
  3672.     AUTO    SBYTE xx, xxx, yy, yyy;
  3673.     AUTO    ABOOL done;
  3674.     PERSIST UBYTE otherfield[FIELDX + 1][FIELDY + 1];
  3675.  
  3676.     for (i = 0; i <= MAGNETS; i++)
  3677.         if (magnet[i].alive && x == magnet[i].x && y == magnet[i].y)
  3678.              magnet[i].alive = FALSE;
  3679.  
  3680.     if (!valid(x, y)) // defensive programming
  3681.     {   return 0;
  3682.  
  3683.         /* AUTO TEXT temp1[SAYLIMIT + 1], temp2[8];
  3684.  
  3685.         strcpy(temp1, "BAD OBJECT AT x: ");
  3686.         stci_d(temp2, x);
  3687.         strcat(temp1, temp2);
  3688.         strcat(temp1, ", y: ");
  3689.         stci_d(temp2, y);
  3690.         strcat(temp1, temp2);
  3691.         strcat(temp1, "!");
  3692.         say(temp1, worm[player].colour);
  3693.         draw(FIELDX + 1, 0, c); // indicates which object
  3694.         Delay(250);
  3695.         clearkybd();
  3696.         anykey(FALSE); */
  3697.     }
  3698.  
  3699.     switch(c)
  3700.     {
  3701.     case BONUS:
  3702.         effect(FXGET_OBJECT);
  3703.         for (i = 0; i <= LETTERS; i++)
  3704.         {   if (!letters[i])
  3705.             {   break;
  3706.         }   }
  3707.         if (i > LETTERS) /* if no spare letters */
  3708.             i = arand(LETTERS);
  3709.         else
  3710.         {   do
  3711.                 i = arand(LETTERS);
  3712.             while (letters[i]);
  3713.         }
  3714.         letters[i] = TRUE;
  3715.         drawletter(FIRSTLETTER + i, NORMAL);
  3716.     break;
  3717.     case AMMO:
  3718.         effect(FXGET_AMMO);
  3719.         worm[player].ammo += arand(4) + 2; /* 2-6 bullets */
  3720.         stat(player, AMMO);
  3721.     break;
  3722.     case ARMOUR:
  3723.         effect(FXGET_OBJECT);
  3724.         worm[player].armour += ADD_MODE + arand(RAND_MODE);
  3725.         stat(player, ARMOUR);
  3726.     break;
  3727.     case NITRO:
  3728.         effect(FXGET_NITRO);
  3729.         worm[player].nitro = TRUE;
  3730.         stat(player, NITRO);
  3731.     break;
  3732.     case BOMB:
  3733.         if (worm[player].armour == 0)
  3734.             draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3735.         else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  3736.         bombblast(HEAD, player, worm[player].x, worm[player].y);
  3737.     break;
  3738.     case POWER:
  3739.         effect(FXGET_POWERUP);
  3740.         if (worm[player].power < POWERLIMIT)
  3741.         {   worm[player].power += 2;
  3742.             stat(player, POWER);
  3743.         }
  3744.     break;
  3745.     case SLAYER:
  3746.         for (i = 0; i <= CREATURES; i++)
  3747.         {   if (creature[i].alive)
  3748.             {   if
  3749.                 (   (   creature[i].species != MISSILE
  3750.                      && creature[i].species != DRIP
  3751.                     )
  3752.                  || creature[i].type != player
  3753.                 )
  3754.                 {   wormkillcreature(player, i);
  3755.                     change(creature[i].x, creature[i].y, EMPTY);
  3756.         }   }   }
  3757.         for (i = 0; i <= 3; i++)
  3758.             if (player != i && worm[i].armour == 0)
  3759.             {   worm[i].alive = FALSE;
  3760.                 worm[i].cause = SLAYER;
  3761.                 worm[i].victor = player;
  3762.             }
  3763.         for (x = 0; x <= FIELDX; x++)
  3764.             for (y = 0; y <= FIELDY; y++)
  3765.                 if (field[x][y] == SLIME)
  3766.                     change(x, y, EMPTY);
  3767.     break;
  3768.     case PROTECTOR:
  3769.         // create protector
  3770.         done = FALSE;
  3771.         for (i = 0; i <= PROTECTORS; i++)
  3772.         {   if (!protector[player][i].alive && !done)
  3773.             {   do
  3774.                 {   protector[player][i].relx = (arand(1) * 2) - 1;
  3775.                     protector[player][i].rely = (arand(1) * 2) - 1;
  3776.                     for (j = 0; j <= PROTECTORS; j++)
  3777.                     {   if
  3778.                         (   i == NOSE
  3779.                          || !protector[player][j].alive
  3780.                          ||  protector[player][j].x != xwrap(worm[player].x + protector[player][i].relx)
  3781.                          ||  protector[player][j].y != ywrap(worm[player].y + protector[player][i].rely)
  3782.                         ) // if we can find an area without a preexisting protector
  3783.                         {   effect(FXBORN_PROTECTOR);
  3784.                             done = TRUE;
  3785.                             protector[player][i].alive = TRUE;
  3786.                             protector[player][i].visible = FALSE;
  3787.                             protector[player][i].last = EMPTY;
  3788.                             if (i == NOSE)
  3789.                             {   worm[player].position = -1;
  3790.                 }   }   }   }
  3791.                 while (!done);
  3792.         }   }
  3793.     break;
  3794.     case MISSILE:
  3795.         for (i = 0; i <= CREATURES; i++)
  3796.         {   if (!creature[i].alive)
  3797.             {   createcreature(MISSILE, i, worm[player].x, worm[player].y, 0, 0, player);
  3798.                 break;
  3799.         }   }
  3800.     break;
  3801.     case LIFE:
  3802.         effect(FXGET_OBJECT);
  3803.         worm[player].lives += arand(4) + 2; /* 2-6 lives */
  3804.         stat(player, LIFE);
  3805.     break;
  3806.     case MULTIPLIER:
  3807.         effect(FXGET_OBJECT);
  3808.         if (worm[player].multi < MULTILIMIT)
  3809.             worm[player].multi *= 2;
  3810.     break;
  3811.     case BIAS:
  3812.         effect(FXGET_OBJECT);
  3813.         worm[player].bias += ADD_MODE + arand(RAND_MODE);
  3814.         stat(player, BIAS);
  3815.     break;
  3816.     case ICE:
  3817.         effect(FXGET_OBJECT);
  3818.         ice += ADD_ICE + arand(RAND_ICE);
  3819.     break;
  3820.     case GROWER:
  3821.         effect(FXGET_GROWER);
  3822.  
  3823.         /* grow dynamite */
  3824.         for (x = 0; x <= FIELDX; x++)
  3825.             for (y = 0; y <= FIELDY; y++)
  3826.                 if (field[x][y] == DYNAMITE)
  3827.                     for (xx = x - 1; xx <= x + 1; xx++)
  3828.                         for (yy = y - 1; yy <= y + 1; yy++)
  3829.                             if (valid(xx, yy))
  3830.                                 if (field[xx][yy] == EMPTY)
  3831.                                     field[xx][yy] = TEMPDYNAMITE;
  3832.         /* grow silver */
  3833.         for (x = 0; x <= FIELDX; x++)
  3834.             for (y = 0; y <= FIELDY; y++)
  3835.                 if (field[x][y] == SILVER)
  3836.                     for (xx = x - 1; xx <= x + 1; xx++)
  3837.                         for (yy = y - 1; yy <= y + 1; yy++)
  3838.                             if (valid(xx, yy))
  3839.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE)
  3840.                                     field[xx][yy] = TEMPSILVER;
  3841.         /* grow gold */
  3842.         for (x = 0; x <= FIELDX; x++)
  3843.             for (y = 0; y <= FIELDY; y++)
  3844.                 if (field[x][y] == GOLD)
  3845.                     for (xx = x - 1; xx <= x + 1; xx++)
  3846.                         for (yy = y - 1; yy <= y + 1; yy++)
  3847.                             if (valid(xx, yy))
  3848.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE || field[xx][yy] == TEMPSILVER)
  3849.                                     field[xx][yy] = TEMPGOLD;
  3850.         /* update field */
  3851.         for (x = 0; x <= FIELDX; x++)
  3852.             for (y = 0; y <= FIELDY; y++)
  3853.                 switch (field[x][y])
  3854.                 {
  3855.                 case TEMPGOLD:
  3856.                     change(x, y, GOLD);
  3857.                 break;
  3858.                 case TEMPSILVER:
  3859.                     change(x, y, SILVER);
  3860.                 break;
  3861.                 case TEMPDYNAMITE:
  3862.                     change(x, y, DYNAMITE);
  3863.                 break;
  3864.                 default:
  3865.                 break;
  3866.                 }
  3867.     break;
  3868.     case TREASURE:
  3869.         treasurer = player;
  3870.         if (level)
  3871.         {   secondsperlevel = 0;
  3872.             leveltype = arand(2);
  3873.             if (leveltype == 0)
  3874.             {   say("Bonus Level: Treasury!", worm[treasurer].colour);
  3875.                 leveltype = TREASURE;
  3876.             } elif (leveltype == 1)
  3877.             {   say("Bonus Level: Drips!", worm[treasurer].colour);
  3878.                 leveltype = DRIP;
  3879.             } else
  3880.             {   // assert(leveltype == 2);
  3881.                 say("Bonus Level: Penguins!", worm[treasurer].colour);
  3882.                 leveltype = PENGUIN;
  3883.         }   }
  3884.         secondsperlevel += ADD_TREASURE + arand(RAND_TREASURE);
  3885.         if (level && leveltype != TREASURE)
  3886.             secondsperlevel *= 2;
  3887.         if (secondsperlevel > TIMELIMIT)
  3888.             secondsperlevel = TIMELIMIT;
  3889.         if (level)
  3890.         {   stat(player, BONUS);
  3891.             reallevel = level;
  3892.             level = 0;
  3893.             newlevel(player);
  3894.         }
  3895.     break;
  3896.     case AFFIXER:
  3897.         effect(FXGET_OBJECT);
  3898.         worm[player].affixer = TRUE;
  3899.         icon(player, AFFIXER);
  3900.     break;
  3901.     case SWITCHER:
  3902.         effect(FXGET_OBJECT);
  3903.         for (x = 0; x <= FIELDX; x++)
  3904.         {   for (y = 0; y <= FIELDY; y++)
  3905.             {   if (players >= 2 && field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL && field[x][y] != FIRSTTAIL + player)
  3906.                 {   change(x, y, FIRSTTAIL + player);
  3907.                 } elif (worm[player].bias)
  3908.                 {   if (field[x][y] >= FIRSTFIRE && field[x][y] <= LASTFIRE && field[x][y] != FIRSTFIRE + player)
  3909.                         change(x, y, FIRSTFIRE + player);
  3910.                     elif (field[x][y] == SLIME)
  3911.                         change(x, y, DYNAMITE);
  3912.         }   }   }
  3913.     break;
  3914.     case HEALER:
  3915.         effect(FXGET_OBJECT);
  3916.         if (worm[player].lives < 100)
  3917.             worm[player].lives = 100;
  3918.         else worm[player].lives = LIVESLIMIT;
  3919.         stat(player, LIFE);
  3920.     break;
  3921.     case UMBRELLA:
  3922.         level += arand(1) + 1;
  3923.         if (level >= levels)
  3924.             level = levels; // fixed?
  3925.         for (i = 0; i <= LETTERS; i++)
  3926.             letters[i] = TRUE;
  3927.     break;
  3928.     case CLOCK:
  3929.         effect(FXGET_OBJECT);
  3930.         secondsperlevel += ADD_CLOCK + arand(RAND_CLOCK);
  3931.         if (secondsperlevel > TIMELIMIT)
  3932.         {   secondsperlevel = TIMELIMIT;
  3933.         }
  3934.     break;
  3935.     case SLOWER:
  3936.         effect(FXGET_OBJECT);
  3937.         for (i = 0; i <= CREATURES; i++)
  3938.             if (creature[i].alive && creature[i].species != MISSILE)
  3939.                 creature[i].speed = (SBYTE) atleast(creature[i].speed * 2, VERYFAST);
  3940.     break;
  3941.     case PULSE:
  3942.         effect(FXGET_PULSE);
  3943.         for (i = 0; i <= CREATURES; i++)
  3944.         {   if (!creature[i].alive && generated <= 7)
  3945.             {   switch (generated)
  3946.                 {
  3947.                 case 0:
  3948.                     xx = 0;
  3949.                     yy = -1;
  3950.                 break;
  3951.                 case 1:
  3952.                     xx = 1;
  3953.                     yy = -1;
  3954.                 break;
  3955.                 case 2:
  3956.                     xx = 1;
  3957.                     yy = 0;
  3958.                 break;
  3959.                 case 3:
  3960.                     xx = 1;
  3961.                     yy = 1;
  3962.                 break;
  3963.                 case 4:
  3964.                     xx = 0;
  3965.                     yy = 1;
  3966.                 break;
  3967.                 case 5:
  3968.                     xx = -1;
  3969.                     yy = 1;
  3970.                 break;
  3971.                 case 6:
  3972.                     xx = -1;
  3973.                     yy = 0;
  3974.                 break;
  3975.                 case 7:
  3976.                     xx = -1;
  3977.                     yy = -1;
  3978.                 break;
  3979.                 default:
  3980.                 break;
  3981.                 }
  3982.  
  3983.                 generated++;
  3984.                 if (xx != worm[player].deltax || yy != worm[player].deltay)
  3985.                 {   d = field[x + xx][y + yy];
  3986.                     if ((d >= FIRSTEMPTY && d <= LASTEMPTY) || (d >= FIRSTTAIL && d <= LASTTAIL) || d <= LASTOBJECT)
  3987.                     {   createcreature(FRAGMENT, i, x + xx, y + yy, xx, yy, 255);
  3988.         }   }   }   }
  3989.     break;
  3990.     case REMNANTS:
  3991.         effect(FXGET_OBJECT);
  3992.         worm[player].remnants = TRUE;
  3993.         icon(player, REMNANTS);
  3994.     break;
  3995.     case SIDESHOT:
  3996.         effect(FXGET_POWERUP);
  3997.         worm[player].sideshot = TRUE;
  3998.         icon(player, SIDESHOT);
  3999.     break;
  4000.     case MAGNET:
  4001.         effect(FXGET_OBJECT);
  4002.         i = 0;
  4003.         field[x][y] = EMPTY; // so that the magnet itself is destroyed
  4004.         for (xx = 0; xx <= FIELDX; xx++)
  4005.             for (yy = 0; yy <= FIELDY; yy++)
  4006.                 if (field[xx][yy] <= LASTOBJECT)
  4007.                 {   while (magnet[i].alive && i < MAGNETS)
  4008.                        i++;
  4009.                     if (i > MAGNETS)
  4010.                     {   break;
  4011.                     } else
  4012.                     {   magnet[i].x      = xx;
  4013.                         magnet[i].y      = yy;
  4014.                         magnet[i].object = field[xx][yy];
  4015.                         magnet[i].player = player;
  4016.                         magnet[i].alive  = TRUE;
  4017.                         i++;
  4018.                 }   }
  4019.     break;
  4020.     case CUTTER:
  4021.         effect(FXGET_OBJECT);
  4022.         worm[player].cutter += ADD_CUTTER + arand(RAND_CUTTER);
  4023.         icon(player, CUTTER);
  4024.     break;
  4025.     case CYCLONE:
  4026.         /* create whirlwind */
  4027.         x = arand(FIELDX);
  4028.         y = arand(FIELDY - 5) + 5;
  4029.         d = field[x][y];
  4030.         if (d >= FIRSTEMPTY && d <= LASTEMPTY)
  4031.         {   for (i = 0; i <= CREATURES; i++)
  4032.             {   if (!creature[i].alive)
  4033.                 {   createcreature(WHIRLWIND, i, x, y, 0, 0, 255);
  4034.                     break;
  4035.         }   }   }
  4036.     break;
  4037.     case LIGHTNING:
  4038.         effect(FXGET_OBJECT);
  4039.         for (xx = 0; xx <= FIELDX; xx++)
  4040.             for (yy = 0; yy <= FIELDY; yy++)
  4041.                 otherfield[xx][yy] = EMPTY;
  4042.         for (xx = 0; xx <= FIELDX; xx++)
  4043.             for (yy = 0; yy <= FIELDY; yy++)
  4044.                 if (field[xx][yy] == FIRSTTAIL + player)
  4045.                     for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  4046.                         for (yyy = yy - 1; yyy <= yy + 1; yyy++)
  4047.                             if (valid(xxx, yyy))
  4048.                             {   d = field[xxx][yyy];
  4049.                                 if (d == ORB
  4050.                                  || d == GOAT
  4051.                                  || d == MISSILE
  4052.                                  || d == PENGUIN
  4053.                                  || d == FISH
  4054.                                  || d == FRAGMENT
  4055.                                  || (d >= FIRSTTAIL && d <= LASTTAIL && d != FIRSTTAIL + player)
  4056.                                  || (d >= FIRSTHEAD && d <= LASTHEAD)
  4057.                                  || (d >= FIRSTDRIP && d <= LASTDRIP)
  4058.                                  || d <= LASTOBJECT)
  4059.                                 {   otherfield[xxx][yyy] = TEMPLIGHTNING;
  4060.                                     draw(xxx, yyy, LIGHTNING);
  4061.                             }   }
  4062.         for (xx = 0; xx <= FIELDX; xx++)
  4063.         {   for (yy = 0; yy <= FIELDY; yy++)
  4064.             {   if (otherfield[xx][yy] == TEMPLIGHTNING)
  4065.                 {   d = field[xx][yy];
  4066.                     if (d >= FIRSTMISSILE && d <= LASTMISSILE)
  4067.                     {   i = whichcreature(xx, yy, MISSILE, 255);
  4068.                         if (player != creature[i].type)
  4069.                         {   wormkillcreature(player, i);
  4070.                             change(xx, yy, EMPTY);
  4071.                         } else drawmissile(xx, yy, i);
  4072.                     } elif (d >= FIRSTDRIP && d <= LASTDRIP)
  4073.                     {   i = whichcreature(xx, yy, DRIP, 255);
  4074.                         if (player != creature[i].type)
  4075.                         {   wormkillcreature(player, i);
  4076.                             change(xx, yy, EMPTY);
  4077.                         } else draw(xx, yy, FIRSTDRIP + player);
  4078.                     } else
  4079.                     {   switch(d)
  4080.                         {
  4081.                         case CLOUD:
  4082.                         case DOG:
  4083.                         case FRAGMENT:
  4084.                         case GOAT:
  4085.                         case OCTOPUS:
  4086.                         case ORB:
  4087.                         case PENGUIN:
  4088.                         case WHIRLWIND:
  4089.                             i = whichcreature(xx, yy, d, 255);
  4090.                             change(xx, yy, EMPTY);
  4091.                         break;
  4092.                         default:
  4093.                             /* eg. tail */
  4094.                             change(xx, yy, EMPTY);
  4095.                         break;
  4096.         }   }   }   }   }
  4097.     break;
  4098.     case PUSHER:
  4099.         effect(FXGET_OBJECT);
  4100.         worm[player].pusher = TRUE;
  4101.         icon(player, PUSHER);
  4102.     break;
  4103.     case FREEDOM:
  4104.         effect(FXGET_OBJECT);
  4105.         worm[player].freedom += ADD_FREEDOM + arand(RAND_FREEDOM);
  4106.         if (worm[player].freedom > FREEDOMLIMIT)
  4107.             worm[player].freedom = FREEDOMLIMIT;
  4108.         icon(player, FREEDOM);
  4109.     break;
  4110.     case ENCLOSER:
  4111.         effect(FXGET_OBJECT);
  4112.         worm[player].encloser = TRUE;
  4113.         icon(player, ENCLOSER);
  4114.     break;
  4115.     case CONVERTER:
  4116.         effect(FXGET_OBJECT);
  4117.         for (i = 0; i <= CREATURES; i++)
  4118.             if (creature[i].alive && creature[i].species == FRAGMENT)
  4119.             {   xx = creature[i].x;
  4120.                 yy = creature[i].y;
  4121.                 creature[i].alive = FALSE;
  4122.                 change(xx, yy, EMPTY);
  4123.                 createcreature(MISSILE, i, xx, yy, 0, 0, player);
  4124.             }
  4125.     break;
  4126.     default:
  4127.         // assert(0);
  4128.     break;
  4129.     }
  4130.     return(score);
  4131. }
  4132.  
  4133. void icon(SBYTE player, UBYTE image)
  4134. {   /* Updates one of the boolean icons. The routine checks
  4135.     the status directly. */
  4136.  
  4137.     SBYTE x, y;
  4138.  
  4139.     if (iso)
  4140.     {   x = -8;
  4141.         y = (FIELDY / 2) - 9 + player;
  4142.     } else
  4143.     {   if (!worm[player].statx)
  4144.            x = -8;
  4145.         else x = FIELDX + 3;
  4146.         if (!worm[player].staty)
  4147.            y = (FIELDY / 2) - 6;
  4148.         else y = (FIELDY / 2) + 5;
  4149.     }
  4150.  
  4151.     switch(image)
  4152.     {
  4153.     case AFFIXER:
  4154.         if (worm[player].affixer)
  4155.             draw(x, y, AFFIXER);
  4156.         else draw(x, y, BLACKENED);
  4157.     break;
  4158.     case PUSHER:
  4159.         if (worm[player].pusher)
  4160.             draw(x + 1, y, PUSHER);
  4161.         else draw(x + 1, y, BLACKENED);
  4162.     break;
  4163.     case REMNANTS:
  4164.         if (worm[player].remnants)
  4165.             draw(x + 2, y, REMNANTS);
  4166.         else draw(x + 2, y, BLACKENED);
  4167.     break;
  4168.     case SIDESHOT:
  4169.         if (worm[player].sideshot)
  4170.             draw(x + 3, y, SIDESHOT);
  4171.         else draw(x + 3, y, BLACKENED);
  4172.     break;
  4173.     case CUTTER:
  4174.         if (worm[player].cutter)
  4175.         {   if (worm[player].cutter < 10)
  4176.             {   if ((r % 4) <= 1)
  4177.                 {   draw(x + 4, y, CUTTER);
  4178.                 } else draw(x + 4, y, BLACKENED);
  4179.             } else draw(x + 4, y, CUTTER);
  4180.         } else draw(x + 4, y, BLACKENED);
  4181.     break;
  4182.     case FREEDOM:
  4183.         if (worm[player].freedom)
  4184.         {   if (worm[player].freedom < 10)
  4185.             {   if ((r % 4) <= 1)
  4186.                 {   draw(x + 5, y, FREEDOM);
  4187.                 } else draw(x + 5, y, BLACKENED);
  4188.             } else draw(x + 5, y, FREEDOM);
  4189.         } else draw(x + 5, y, BLACKENED);
  4190.     break;
  4191.     case ENCLOSER:
  4192.         if (worm[player].encloser)
  4193.             draw(x + 6, y, ENCLOSER);
  4194.         else draw(x + 6, y, BLACKENED);
  4195.     break;
  4196.     default:
  4197.     break;
  4198. }   }
  4199.  
  4200. MODULE void wormcol(SBYTE player, SBYTE x, SBYTE y)
  4201. {   ABOOL flag;
  4202.     UBYTE c = field[x][y], d;
  4203.     SBYTE i, xx, yy;
  4204.     ULONG score = 0;
  4205.  
  4206.     if (c >= FIRSTHEAD && c <= LASTHEAD)
  4207.         wormworm(x, y, player, c - FIRSTHEAD);
  4208.     elif (c == TIMEBOMB)
  4209.     {   /* push timebomb */
  4210.         i = whichcreature(x, y, TIMEBOMB, 255);
  4211.         if (valid(x + worm[player].deltax, y + worm[player].deltay))
  4212.         {   d = field[x + worm[player].deltax][y + worm[player].deltay];
  4213.             if (d <= LASTEMPTY)
  4214.             {   creature[i].x += worm[player].deltax;
  4215.                 creature[i].y += worm[player].deltay;
  4216.                 field[creature[i].x][creature[i].y] = TIMEBOMB;
  4217.                 draw(creature[i].x, creature[i].y, ZERO + creature[i].time);
  4218.             } else // oops, you've fucked up! :-( Timebomb explodes!
  4219.             {   if (worm[player].armour == 0)
  4220.                     draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4221.                 else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4222.                 bombblast(HEAD, player, worm[player].x, worm[player].y);
  4223.                 creature[i].alive = FALSE;
  4224.         }   }
  4225.         else
  4226.         {   score += creature[i].score;
  4227.     }   }
  4228.     elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  4229.         protworm(x, y, c - FIRSTPROTECTOR, player);
  4230.     elif (c >= FIRSTMISSILE && c <= LASTMISSILE)
  4231.     {   i = whichcreature(x, y, c, 255);
  4232.         wormcreature(player, i);
  4233.     } elif (c >= FIRSTDRIP && c <= LASTDRIP)
  4234.     {   i = whichcreature(x, y, DRIP, 255);
  4235.         wormcreature(player, i);
  4236.     } elif
  4237.     (   c == STONE
  4238.      || c == METAL
  4239.      || c == WOOD
  4240.      || c == FISH
  4241.      || c == GOAT
  4242.      || c == OCTOPUS
  4243.      || (c >= FIRSTTAIL && c <= LASTTAIL)
  4244.     ) // if you've hit something that is pushable
  4245.     {   flag = TRUE; // flag is whether you deserve to die
  4246.         if (worm[player].pusher)
  4247.         {   xx = x + worm[player].deltax;
  4248.             yy = y + worm[player].deltay;
  4249.             if (valid(xx, yy))
  4250.             {   d = field[xx][yy];
  4251.                 if (d <= LASTEMPTY)
  4252.                 // if you're pushing the square into a square which
  4253.                 // has an object or is empty/silver/gold
  4254.                 {   flag = FALSE; // then you don't deserve to die
  4255.                     if
  4256.                     (   c == FISH
  4257.                      || c == GOAT
  4258.                      || c == OCTOPUS
  4259.                     )
  4260.                     {   i = whichcreature(x, y, c, 255);
  4261.                         creature[i].x = xx;
  4262.                         creature[i].y = yy;
  4263.                         creature[i].visible = FALSE;
  4264.                     }
  4265.                     field[xx][yy] = c;
  4266.                     draw(xx, yy, c);
  4267.             }   }                 
  4268.             else // if pushing off the field edges
  4269.             {   flag = FALSE; // then you don't deserve to die
  4270.                 // kill the creature
  4271.                 if
  4272.                 (   c == FISH
  4273.                  || c == GOAT
  4274.                  || c == OCTOPUS
  4275.                 )
  4276.                 {   i = whichcreature(x, y, c, 255);
  4277.                     wormkillcreature(player, i);
  4278.         }   }   }
  4279.         if (flag) // if we deserve to die
  4280.         {   if (c >= FIRSTTAIL && c <= LASTTAIL) // if we're pushing/hitting tail
  4281.             {   if (worm[player].armour > 0)
  4282.                 {   effect(FXUSE_ARMOUR);
  4283.                     if (players > 1)
  4284.                     {   if (player == c - FIRSTTAIL)
  4285.                         {   score += POINTS_TURNSILVER;
  4286.                             worm[player].last = SILVER;
  4287.                         } else
  4288.                         {   score += POINTS_TURNGOLD;
  4289.                             worm[player].last = GOLD;
  4290.                 }   }   }
  4291.                 elif (!enclosed)
  4292.                 {   worm[player].cause = c;
  4293.                     worm[player].alive = FALSE;
  4294.                     worm[player].victor = c - FIRSTTAIL;
  4295.             }   }
  4296.             else
  4297.             {   if
  4298.                 (   c == FISH
  4299.                  || c == GOAT
  4300.                  || c == OCTOPUS
  4301.                 )
  4302.                 {   i = whichcreature(x, y, c, 255);
  4303.                     wormcreature(player, i);
  4304.                 } elif (worm[player].armour == 0)
  4305.                 {   worm[player].cause = c;
  4306.                     worm[player].alive = FALSE;
  4307.                     worm[player].victor = -1;
  4308.                 }
  4309.                 if (c != WOOD)
  4310.                 {   ramming(player);
  4311.     }   }   }   }
  4312.     elif (c == SLIME)
  4313.     {   if (worm[player].armour == 0)
  4314.         {   worm[player].cause = c;
  4315.             worm[player].alive = FALSE;
  4316.             worm[player].victor = -1;
  4317.     }   }
  4318.     elif
  4319.     (   c == BIRD
  4320.      || c == CLOUD
  4321.      || c == DOG
  4322.      || c == FRAGMENT
  4323.      || c == ORB
  4324.      || c == PENGUIN
  4325.      || c == WHIRLWIND
  4326.     )
  4327.     {   i = whichcreature(x, y, c, 255);
  4328.         wormcreature(player, i);
  4329.     } elif (c == TELEPORT)
  4330.     {   i = whichteleport(x, y);
  4331.         if (blocked(i, worm[player].deltax, worm[player].deltay))
  4332.         {   worm[player].cause = TELEPORT;
  4333.             worm[player].victor = -1;
  4334.             worm[player].alive = FALSE;
  4335.             ramming(player);
  4336.         } else
  4337.         {   effect(FXUSE_TELEPORT);
  4338.             worm[player].x = xwrap(teleport[level][partner(i)].x + worm[player].deltax);
  4339.             worm[player].y = ywrap(teleport[level][partner(i)].y + worm[player].deltay);
  4340.     }   }
  4341.     elif (c >= FIRSTFIRE && c <= LASTFIRE)
  4342.     {   if (player != c - FIRSTFIRE && worm[player].armour == 0)
  4343.         {   worm[player].cause = REMNANTS;
  4344.             worm[player].victor = c - FIRSTFIRE;
  4345.             worm[player].alive = FALSE;
  4346.     }   }
  4347.     else bothcol(player, x, y);
  4348.     wormscore(player, score);
  4349. }
  4350.  
  4351. AGLOBAL void drawhead(SBYTE player, SBYTE x, SBYTE y)
  4352. {   if (worm[player].alive)
  4353.     {   if (worm[player].armour == 0)
  4354.         {   draw(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4355.             worm[player].flashed = FALSE;
  4356.         } else
  4357.         {   if (worm[player].armour < 10)
  4358.             {   if (!worm[player].flashed)
  4359.                 {   draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4360.                 } else draw(worm[player].x, worm[player].y, WHITENED);
  4361.                 worm[player].flashed = !worm[player].flashed;
  4362.             } else draw(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  4363.     }   }
  4364.     else draw(worm[player].x, worm[player].y, SKULL);
  4365. }
  4366.  
  4367. AGLOBAL void drawsquare(SBYTE x, SBYTE y)
  4368. {   UBYTE which;
  4369.  
  4370.     if (field[x][y] == DOG)
  4371.     {   which = whichcreature(x, y, DOG, 255);
  4372.         if (!creature[which].dormant)
  4373.         {   draw(x, y, DOGDORMANT);
  4374.         } elif (creature[which].dormant <= CHASING)
  4375.         {   draw(x, y, DOGAWAKENING);
  4376.         } else
  4377.         {   draw(x, y, DOG);
  4378.     }   }
  4379.     elif (field[x][y] >= FIRSTHEAD && field[x][y] <= LASTHEAD)
  4380.     {   drawhead(field[x][y] - FIRSTHEAD, x, y);
  4381.     } else
  4382.     {   draw(x, y, field[x][y]);
  4383. }   }
  4384.  
  4385. MODULE void updatearrow(SBYTE arrowy)
  4386. {   SBYTE i, var = -1;
  4387.  
  4388.     /* var of:
  4389.                   -2         : many there
  4390.                   -1         : nothing there
  4391.                  0-3         : just that worm,
  4392.        FIRSTLETTER-LASTLETTER: just that letter */
  4393.  
  4394.     for (i = 0; i <= 3; i++)
  4395.         if (worm[i].control != NONE && worm[i].y == arrowy && (worm[i].lives || field[worm[i].x][worm[i].y] == SKULL))
  4396.             if (var == -1)
  4397.                 var = i;
  4398.             else var = -2;
  4399.     if (lettery == arrowy)
  4400.         if (var == -1)
  4401.             var = lettertype;
  4402.         else var = -2;
  4403.     if (var == -2)
  4404.         draw(ARROWX, arrowy, ALL);
  4405.     elif (var == -1)
  4406.         draw(ARROWX, arrowy, BLACKENED);
  4407.     elif (var >= FIRSTLETTER && var <= LASTLETTER)
  4408.         draw(ARROWX, arrowy, var);
  4409.     else
  4410.     {   // assert(var >= 0 && var <= 3);
  4411.         if (worm[var].lives)
  4412.             draw(ARROWX, arrowy, FIRSTARROW + var);
  4413.         else draw(ARROWX, arrowy, SKULL);
  4414. }   }
  4415.  
  4416. MODULE void __inline bangdynamite(SBYTE x, SBYTE y, SBYTE player)
  4417. {   SBYTE xx, yy;
  4418.  
  4419.     // Infects (turns to bang-dynamite) all surrounding dynamite.
  4420.  
  4421.     for (xx = x - 1; xx <= x + 1; xx++)
  4422.     {   for (yy = y - 1; yy <= y + 1; yy++)
  4423.         {   if (valid(xx, yy))
  4424.             {   if (field[xx][yy] == DYNAMITE)
  4425.                 {   field[xx][yy] = TEMPBANGDYNAMITE;
  4426.                     worm[player].dynamitescore += POINTS_DYNAMITE;
  4427.                     infector[xx][yy] = player;
  4428. }   }   }   }   }
  4429.  
  4430. MODULE void octopusfire(UBYTE which)
  4431. {   UBYTE i;
  4432.     SBYTE x, y, deltax, deltay;
  4433.  
  4434.     for (i = 0; i <= CREATURES; i++)
  4435.     {   if (!creature[i].alive)
  4436.         {   switch(creature[which].dir)
  4437.             {
  4438.             case 0:
  4439.                 deltax = 0;
  4440.                 deltay = -1;
  4441.             break;
  4442.             case 1:
  4443.                 deltax = 1;
  4444.                 deltay = -1;
  4445.             break;
  4446.             case 2:
  4447.                 deltax = 1;
  4448.                 deltay = 0;
  4449.             break;
  4450.             case 3:
  4451.                 deltax = 1;
  4452.                 deltay = 1;
  4453.             break;
  4454.             case 4:
  4455.                 deltax = 0;
  4456.                 deltay = 1;
  4457.             break;
  4458.             case 5:
  4459.                 deltax = -1;
  4460.                 deltay = 1;
  4461.             break;
  4462.             case 6:
  4463.                 deltax = -1;
  4464.                 deltay = 0;
  4465.             break;
  4466.             case 7:
  4467.                 deltax = -1;
  4468.                 deltay = -1;
  4469.             break;
  4470.             default:
  4471.             break;
  4472.             }
  4473.             x = creature[which].x + deltax;
  4474.             y = creature[which].y + deltay;
  4475.             if (valid(x, y) && field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  4476.             {   effect(FXGET_PULSE);
  4477.                 createcreature(FRAGMENT, i, x, y, deltax, deltay, 255);
  4478.                 goto out;
  4479.     }   }   }
  4480.  
  4481. out:
  4482.     if (++creature[which].dir == 8)
  4483.     {   creature[which].dir = -1;
  4484. }   }
  4485.  
  4486. MODULE void createcreature(UBYTE species, UBYTE which, SBYTE x, SBYTE y, SBYTE deltax, SBYTE deltay, UBYTE player)
  4487. {   switch(species)
  4488.     {
  4489.     case FRAGMENT:
  4490.         creature[which].speed    = SPEED_FRAGMENT;
  4491.         creature[which].score    = SCORE_FRAGMENT;
  4492.         creature[which].hardness = HARDNESS_FRAGMENT;
  4493.         creature[which].visible  = TRUE;
  4494.         creature[which].last     = EMPTY;
  4495.         change(x, y, FRAGMENT);
  4496.     break;
  4497.     case OCTOPUS:
  4498.         creature[which].speed    = SPEED_OCTOPUS;
  4499.         creature[which].score    = SCORE_OCTOPUS;
  4500.         creature[which].hardness = HARDNESS_OCTOPUS;
  4501.         creature[which].visible  = TRUE;
  4502.         creature[which].last     = field[x][y];
  4503.         creature[which].dir      = -1;
  4504.         change(x, y, OCTOPUS);
  4505.     break;
  4506.     case FISH:
  4507.         creature[which].speed    = SPEED_FISH;
  4508.         creature[which].score    = SCORE_FISH;
  4509.         creature[which].hardness = HARDNESS_FISH;
  4510.         creature[which].visible  = TRUE;
  4511.         creature[which].last     =
  4512.         creature[which].oldlast  = field[x][y];
  4513.         change(x, y, FISH);
  4514.     break;
  4515.     case GOAT:
  4516.         effect(FXBORN_GOAT);
  4517.         creature[which].speed    = SPEED_GOAT;
  4518.         creature[which].score    = SCORE_GOAT;
  4519.         creature[which].hardness = HARDNESS_GOAT;
  4520.         creature[which].visible  = TRUE;
  4521.         creature[which].last     =
  4522.         creature[which].oldlast  = field[x][y];
  4523.         change(x, y, GOAT);
  4524.     break;
  4525.     case DOG:
  4526.         creature[which].speed    = SPEED_DOG;
  4527.         creature[which].score    = SCORE_DOG;
  4528.         creature[which].hardness = HARDNESS_DOG;
  4529.         creature[which].visible  = TRUE;
  4530.         creature[which].last     = EMPTY;
  4531.         creature[which].pos      = -1;
  4532.         creature[which].dormant  = DORMANT; /* dormant */
  4533.         field[x][y] = DOG;
  4534.         draw(x, y, DOGDORMANT);
  4535.     break;
  4536.     case ORB:
  4537.         effect(FXBORN_ORB);
  4538.         creature[which].speed    = SPEED_ORB;
  4539.         creature[which].score    = SCORE_ORB;
  4540.         creature[which].hardness = HARDNESS_ORB;
  4541.         creature[which].visible  = TRUE;
  4542.         creature[which].last     = EMPTY;
  4543.         creature[which].multi    = 1;
  4544.         change(x, y, ORB);
  4545.     break;
  4546.     case CLOUD:
  4547.         creature[which].speed    = SPEED_CLOUD;
  4548.         creature[which].score    = SCORE_CLOUD;
  4549.         creature[which].hardness = HARDNESS_CLOUD;
  4550.         creature[which].visible  = TRUE;
  4551.         creature[which].last     = EMPTY;
  4552.         change(x, y, CLOUD);
  4553.     break;
  4554.     case PENGUIN:
  4555.         effect(FXBORN_PENGUIN);
  4556.         creature[which].speed    = SPEED_PENGUIN;
  4557.         creature[which].score    = SCORE_PENGUIN;
  4558.         creature[which].hardness = HARDNESS_PENGUIN;
  4559.         creature[which].visible  = TRUE;
  4560.         creature[which].last     = EMPTY;
  4561.         change(x, y, PENGUIN);
  4562.     break;
  4563.     case TIMEBOMB:
  4564.         creature[which].speed    = SPEED_TIMEBOMB;
  4565.         creature[which].score    = SCORE_TIMEBOMB;
  4566.         creature[which].hardness = HARDNESS_TIMEBOMB;
  4567.         creature[which].last     = EMPTY;
  4568.         creature[which].time     = 10;
  4569.         creature[which].visible  = TRUE;
  4570.         field[x][y] = TIMEBOMB;
  4571.         draw(x, y, ZERO + 9);
  4572.     break;
  4573.     case DRIP:
  4574.         effect(FXBORN_DRIP);
  4575.         creature[which].speed    = SPEED_DRIP;
  4576.         creature[which].score    = SCORE_DRIP;
  4577.         creature[which].hardness = HARDNESS_DRIP;
  4578.         creature[which].last     = EMPTY;
  4579.         creature[which].type     = player;
  4580.         creature[which].visible  = TRUE;
  4581.         change(x, y, FIRSTDRIP + creature[which].type);
  4582.     break;
  4583.     case WHIRLWIND:
  4584.         effect(FXGET_CYCLONE);
  4585.         creature[which].speed    = SPEED_WHIRLWIND;
  4586.         creature[which].score    = SCORE_WHIRLWIND;
  4587.         creature[which].hardness = HARDNESS_WHIRLWIND;
  4588.         creature[which].last     = EMPTY;
  4589.         creature[which].visible  = TRUE;
  4590.         change(x, y, WHIRLWIND);
  4591.     break;
  4592.     case MISSILE:
  4593.         effect(FXBORN_MISSILE);
  4594.         creature[which].score    = SCORE_MISSILE;
  4595.         creature[which].speed    = SPEED_MISSILE;
  4596.         creature[which].hardness = HARDNESS_MISSILE;
  4597.         creature[which].visible  = FALSE;
  4598.         creature[which].last     = EMPTY;
  4599.         creature[which].type     = player;
  4600.         creature[which].frame    = 0;
  4601.     break;
  4602.     case BIRD:
  4603.         creature[which].speed    = SPEED_BIRD;
  4604.         creature[which].score    = SCORE_BIRD;
  4605.         creature[which].hardness = HARDNESS_BIRD;
  4606.         creature[which].visible  = TRUE;
  4607.         creature[which].last     = EMPTY;
  4608.         creature[which].frame    = 0;
  4609.         creature[which].dir      = 1;
  4610.         creature[which].type     = 255;
  4611.         change(x, y, BIRD);
  4612.     break;
  4613.     case OTTER:
  4614.         creature[which].speed    = SPEED_OTTER;
  4615.         creature[which].score    = SCORE_OTTER;
  4616.         creature[which].hardness = HARDNESS_OTTER;
  4617.         creature[which].visible  = TRUE;
  4618.         creature[which].last     = STONE; // should really check whether it should be dynamite instead
  4619.         if (x == 0)
  4620.         {   creature[which].going    = OTTER_DOWN;
  4621.             creature[which].journey  = OTTER_RIGHT;
  4622.         } else
  4623.         {   creature[which].going    = OTTER_UP;
  4624.             creature[which].journey  = OTTER_LEFT;
  4625.         }
  4626.         field[x][y] = OTTER;
  4627.         draw(x, y, OTTER);
  4628.     default:
  4629.     break;
  4630.     }
  4631.  
  4632.     creature[which].alive   = TRUE;
  4633.     creature[which].x       = x;
  4634.     creature[which].y       = y;
  4635.     creature[which].deltax  = deltax;
  4636.     creature[which].deltay  = deltay;
  4637.     creature[which].species = species;
  4638. }
  4639.  
  4640. MODULE ULONG arand(ULONG number)
  4641. {   // Returns a value between 0 and number, inclusive.
  4642.  
  4643.     return(rand() % (number + 1));
  4644. }
  4645.  
  4646. MODULE void protcreature(UBYTE player, UBYTE which)
  4647. {   UBYTE i;
  4648.  
  4649.     /* Handles collisions between protectors and creatures. */
  4650.  
  4651.     switch(creature[which].species)
  4652.     {
  4653.     case BIRD:
  4654.     case CLOUD:
  4655.     case DOG:
  4656.     case DRIP:
  4657.     case ORB:
  4658.     case PENGUIN:
  4659.         effect(FXUSE_PROTECTOR);
  4660.         wormkillcreature(player, which);
  4661.     break;
  4662.     case FRAGMENT:
  4663.         effect(FXUSE_PROTECTOR);
  4664.         reflect(which);
  4665.     break;
  4666.     case MISSILE:
  4667.         if (player != creature[which].type)
  4668.         {   effect(FXUSE_PROTECTOR);
  4669.             wormkillcreature(player, which);
  4670.         } else creature[which].visible = FALSE;
  4671.     break;
  4672.     case WHIRLWIND:
  4673.         for (i = 0; i <= PROTECTORS; i++)
  4674.         {   if
  4675.             (   protector[player][i].alive
  4676.              && protector[player][i].x == creature[which].x
  4677.              && protector[player][i].y == creature[which].y
  4678.             )
  4679.             {   protector[player][i].alive = FALSE;
  4680.         }   }
  4681.     break;
  4682.     default:
  4683.     break;
  4684. }   }
  4685.  
  4686. MODULE void wormcreature(UBYTE player, UBYTE which)
  4687. {   /* Handles collisions between worms and creatures. */
  4688.  
  4689.     switch(creature[which].species)
  4690.     {
  4691.     case CLOUD:
  4692.         wormkillcreature(player, which);
  4693.         if (worm[player].armour == 0)
  4694.         {   worm[player].alive = FALSE;
  4695.             worm[player].cause = CLOUD;
  4696.             worm[player].victor = -1;
  4697.         }
  4698.     break;
  4699.     case DOG:
  4700.         if (creature[which].dormant == DORMANT)
  4701.         {   effect(FXBORN_DOG);
  4702.             creature[which].dormant = AWAKENING;
  4703.             creature[which].type    = player;
  4704.             worm[player].last       = DOG;
  4705.         } else
  4706.         {   wormkillcreature(player, which);
  4707.             if (worm[player].armour == 0)
  4708.             {   worm[player].alive  = FALSE;
  4709.                 worm[player].cause  = DOG;
  4710.                 worm[player].victor = -1;
  4711.         }   }
  4712.     break;
  4713.     case DRIP:
  4714.         wormkillcreature(player, which);
  4715.         if (player != creature[which].type && worm[player].armour == 0)
  4716.         {   worm[player].alive  = FALSE;
  4717.             worm[player].cause  = FIRSTDRIP + creature[which].type;
  4718.             worm[player].victor = -1;
  4719.         }
  4720.     break;
  4721.     case FISH:
  4722.     case GOAT:
  4723.     case OCTOPUS:
  4724.         worm[player].alive  = FALSE;
  4725.         worm[player].cause  = creature[which].species;
  4726.         worm[player].victor = -1;
  4727.     break;
  4728.     case FRAGMENT:
  4729.         if (worm[player].armour > 0)
  4730.         {   effect(FXUSE_ARMOUR);
  4731.             reflect(which);
  4732.         } else
  4733.         {   wormkillcreature(player, which);
  4734.             worm[player].cause  = FRAGMENT;
  4735.             worm[player].victor = -1;
  4736.             worm[player].alive  = FALSE;
  4737.         }
  4738.     break;
  4739.     case MISSILE:
  4740.         if (creature[which].type == player)
  4741.         {   creature[which].visible = FALSE;
  4742.         } else
  4743.         {   wormkillcreature(player, which);
  4744.             if (worm[player].armour == 0)
  4745.             {   worm[player].cause  = FIRSTMISSILE + creature[which].type;
  4746.                 worm[player].victor = creature[which].type;
  4747.                 worm[player].alive  = FALSE;
  4748.             } else effect(FXUSE_ARMOUR);
  4749.         }
  4750.     break;
  4751.     case BIRD:
  4752.     case PENGUIN:
  4753.     case ORB:
  4754.         wormkillcreature(player, which);
  4755.         if (worm[player].armour > 0)
  4756.         {   effect(FXUSE_ARMOUR);
  4757.         } else
  4758.         {   worm[player].cause = creature[which].species;
  4759.             worm[player].victor = -1;
  4760.             worm[player].alive = FALSE;
  4761.         }
  4762.     break;
  4763.     case WHIRLWIND:
  4764.         worm[player].cause  = WHIRLWIND;
  4765.         worm[player].victor = -1;
  4766.         worm[player].alive  = FALSE;
  4767.     break;
  4768.     default:
  4769.     break;
  4770. }   }
  4771.  
  4772. MODULE void creaturecreature(UBYTE which1, UBYTE which2)
  4773. {   if (creature[which1].hardness > creature[which2].hardness)
  4774.     {   creature[which2].alive = FALSE;
  4775.         if (creature[which1].species == MISSILE)
  4776.         {   wormkillcreature(creature[which1].type, which2);
  4777.     }   }
  4778.     elif (creature[which1].hardness < creature[which2].hardness)
  4779.     {   creature[which1].alive = FALSE;
  4780.         if (creature[which2].species == MISSILE)
  4781.         {   wormkillcreature(creature[which2].type, which1);
  4782.     }   }
  4783.     else
  4784.     {   creature[which1].alive =
  4785.         creature[which2].alive = FALSE;
  4786.         change(creature[which1].x, creature[which1].y, BONUS);
  4787. }   }
  4788.  
  4789. /* NAME     align -- right-justify a string within another string
  4790. SYNOPSIS    align(STRPTR, SBYTE, TEXT);
  4791. FUNCTION    Moves all text in a string to the right, padding with
  4792.             spaces. Does not itself add a null terminator.
  4793. INPUTS      string - pointer to the string of text
  4794.               size - size in characters of the containing string
  4795.             filler - what to pad the left of the string with
  4796. NOTE        Null terminators are written over by this function, but that
  4797.             does not matter, because calling functions use Text() with an
  4798.             explicit length. This function only works with monospaced
  4799.             fonts. */
  4800.  
  4801. AGLOBAL void align(STRPTR string, SBYTE size, TEXT filler)
  4802. {   SBYTE i, shift, length;
  4803.  
  4804.     length = strlen((const char*) string);
  4805.     shift = size - length;
  4806.     for (i = 1; i <= length; i++)
  4807.         *(string + size - i) = *(string + size - i - shift);
  4808.     for (i = 0; i <= shift - 1; i++)
  4809.         *(string + i) = filler;
  4810. }
  4811.  
  4812. MODULE void ReadGameports(void)
  4813. {   ReadStandardJoystick(0);
  4814.     ReadStandardJoystick(1);
  4815.     ReadAdapterJoystick(2);
  4816.     ReadAdapterJoystick(3);
  4817.     ReadGamepads();
  4818. }
  4819.  
  4820. MODULE void drawmissile(SBYTE x, SBYTE y, UBYTE which)
  4821. {   draw(x, y, missileframes[creature[which].type][creature[which].frame]);
  4822. }
  4823.  
  4824. MODULE void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize)
  4825. {   AUTO SBYTE i, x, y, leftx, rightx, topy, bottomy;
  4826.     AUTO UBYTE c;
  4827.     PERSIST struct
  4828.     {   SBYTE deltax[4], deltay[4];
  4829.     } deltas[4] =
  4830.     { { { 0, -1,  0,  1}, // northwest
  4831.         {-1,  0,  1,  0}
  4832.       },
  4833.       { { 0,  1,  0, -1}, // northeast
  4834.         {-1,  0,  1,  0}
  4835.       },
  4836.       { { 0,  1,  0, -1}, // southeast
  4837.         { 1,  0, -1,  0}
  4838.       },
  4839.       { { 0, -1,  0,  1}, // southwest
  4840.         { 1,  0, -1,  0}
  4841.     } };
  4842.     PERSIST struct
  4843.     {   SBYTE leftx, rightx, topy, bottomy;
  4844.     } enclose[4] =
  4845.     { {-127,   -1, -127,  -1 }, // northwest
  4846.       {   1,  127, -127,  -1 }, // northeast
  4847.       {   1,  127,    1, 127 }, // southeast
  4848.       {-127,   -1,    1, 127 }  // southwest
  4849.     };
  4850.  
  4851.     x = worm[player].x;
  4852.     y = worm[player].y; // for speed
  4853.  
  4854.     for (i = 0; i <= verticalsize; i++)
  4855.     {   x += deltas[direction].deltax[0];
  4856.         y += deltas[direction].deltay[0];
  4857.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  4858.         {   return;
  4859.     }   }
  4860.     for (i = 0; i <= horizontalsize; i++)
  4861.     {   x += deltas[direction].deltax[1];
  4862.         y += deltas[direction].deltay[1];
  4863.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  4864.         {   return;
  4865.     }   }
  4866.     for (i = 0; i <= verticalsize; i++)
  4867.     {   x += deltas[direction].deltax[2];
  4868.         y += deltas[direction].deltay[2];
  4869.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  4870.         {   return;
  4871.     }   }
  4872.     for (i = 0; i <= horizontalsize - 1; i++)
  4873.     {   x += deltas[direction].deltax[3];
  4874.         y += deltas[direction].deltay[3];
  4875.         if ((!valid(x, y)) || field[x][y] != FIRSTTAIL + player)
  4876.         {   return;
  4877.     }   }
  4878.  
  4879.     effect(FXDO_ENCLOSE);
  4880.     enclosed = TRUE;
  4881.     if (enclose[direction].leftx < -1)
  4882.         enclose[direction].leftx = -horizontalsize;
  4883.     elif (enclose[direction].leftx > 1)
  4884.         enclose[direction].leftx = horizontalsize + 1;
  4885.     if (enclose[direction].rightx < -1)
  4886.         enclose[direction].rightx = -(horizontalsize + 1);
  4887.     elif (enclose[direction].rightx > 1)
  4888.         enclose[direction].rightx = horizontalsize;
  4889.     if (enclose[direction].topy < -1)
  4890.         enclose[direction].topy = -verticalsize;
  4891.     elif (enclose[direction].topy > 1)
  4892.         enclose[direction].topy = verticalsize + 1;
  4893.     if (enclose[direction].bottomy < -1)
  4894.         enclose[direction].bottomy = -(verticalsize + 1);
  4895.     elif (enclose[direction].bottomy > 1)
  4896.         enclose[direction].bottomy = verticalsize;
  4897.  
  4898.       leftx = worm[player].x + enclose[direction].leftx;
  4899.      rightx = worm[player].x + enclose[direction].rightx;
  4900.        topy = worm[player].y + enclose[direction].topy;
  4901.     bottomy = worm[player].y + enclose[direction].bottomy;
  4902.     // assert(leftx >= 0 && rightx <= FIELDX && topy >= 0 && bottomy <= FIELDY && leftx < rightx && topy < bottomy);
  4903.  
  4904.     for (x = leftx; x <= rightx; x++)
  4905.     {   for (y = topy; y <= bottomy; y++)
  4906.         {   c = field[x][y];
  4907.             if ((c >= FIRSTEMPTY && c <= LASTEMPTY) || (c >= FIRSTTAIL && c <= LASTTAIL))
  4908.             {   if (worm[player].bias)
  4909.                 {   change(x, y, GOLD);
  4910.                     wormscore(player, POINTS_ENCLOSURE + POINTS_TURNGOLD);
  4911.                 } elif (player != c - FIRSTTAIL)
  4912.                 {   change(x, y, FIRSTTAIL + player);
  4913.                     wormscore(player, POINTS_ENCLOSURE);
  4914. }   }   }   }   }
  4915.